Skip to content

feat: implement native global error handler (OnError) - #512

Merged
regyssilveira merged 1 commit into
HashLoad:masterfrom
regyssilveira:feature/global-error-handler
Jul 10, 2026
Merged

feat: implement native global error handler (OnError)#512
regyssilveira merged 1 commit into
HashLoad:masterfrom
regyssilveira:feature/global-error-handler

Conversation

@regyssilveira

Copy link
Copy Markdown
Contributor

Pull Request: Feat/Global Error Handler (OnError)

📋 Descrição

Este Pull Request introduz o suporte nativo a um Manipulador Global de Erros (OnError) no framework Horse.

Através deste novo mecanismo, é possível registrar um único callback centralizado para capturar, tratar e formatar todas as exceções não tratadas disparadas durante o ciclo de vida das requisições (seja dentro de middlewares globais, de grupo ou nos próprios handlers de rotas).

Foi mantido o comportamento antigo, bastando para tal não informar o novo manipulador, quando isso não é feito nada muda e o Horse trabalha como sempre trabalhou.


🛠️ Alterações

Core e Roteadores

  • Assinatura Clássica: Declarado o tipo THorseOnError como um ponteiro de procedure clássica (procedure(const ARequest: THorseRequest; const AResponse: THorseResponse; const AException: Exception)), assegurando compatibilidade imediata com compiladores Delphi XE7+ e Lazarus/FPC (sem exigir suporte a métodos anônimos).
  • Registro Global: Adicionados os métodos OnError, HasOnError e ExecuteOnError em THorseCore (e expostos via THorse).
  • Tratamento no Pipeline:
    • Router Padrão: Envelopada a execução de callbacks no TNextCaller.Next (em Horse.Core.RouterTree.NextCaller.pas) e THorseRouterTree.Execute (em Horse.Core.RouterTree.pas) com blocos try ... except.
    • Router Radix: Envelopada a execução no TRadixFlow.Next e THorseRadixRouter.Execute (em Horse.Core.Router.Radix.pas) de forma análoga.
  • Segurança e Isolamento (Safety):
    • Exceções de controle (EHorseCallbackInterrupted e EHorseException) são filtradas e tratadas nativamente pelo framework, não acionando o callback do OnError.
    • Se o próprio callback do usuário registrado no OnError lançar uma exceção de forma imprevista, o framework captura essa falha internamente de forma robusta e responde com HTTP 500 detalhando a causa (evitando travamentos no socket ou vazamentos).
  • Propagação Inteligente (Retrocompatibilidade): Se o OnError não estiver registrado, o framework funciona exatamente como antes: as exceções se propagam de volta até o provedor do servidor HTTP para manter o comportamento original. A única melhoria é que a resposta default de contingência HTTP 500 passa a detalhar a causa real da exceção (ex: 'Internal Application Error: ' + E.Message), em vez de exibir apenas o texto estático genérico fixo.

Documentação, IA Skills e Amostras

  • Samples: Criado o projeto de console demonstrativo samples/delphi/console_error_handler/ e integrado em Samples.groupproj.
  • Documentação: Atualizados os guias doc/middleware.md e doc/middleware.pt-BR.md detalhando as características de funcionamento e registro do OnError.
  • AI Skills: Atualizado o arquivo de skill doc/skills/horse-middlewares/SKILL.md para orientar agentes no uso correto da API global de tratamento de erros.
  • Roadmap: Movida a funcionalidade de pendente para concluída em doc/roadmap/README.md e doc/roadmap/prioritization_matrix.md.

🧪 Testes Realizados

Foi desenvolvida uma suíte abrangente de testes unitários integrados em tests/src/tests/Tests.Api.Console.pas cobrindo os seguintes cenários:

  1. TestOnErrorDefault500: Validação do comportamento padrão do framework que responde com HTTP 500 contendo a causa explícita do erro na ausência de um manipulador OnError.
  2. TestOnErrorCustomHandler: Validação do manipulador customizado do usuário alterando o código de status para HTTP 503 e customizando a mensagem do corpo.
  3. TestOnErrorCallbackCrash: Validação da contingência de segurança (safety) do framework caso o próprio callback do usuário lance uma exceção.
  4. TestOnErrorHorseException: Validação de que exceções nativas de controle (EHorseException) não disparam o OnError e seguem o fluxo HTTP esperado.

A suíte de testes (com todos os 157 testes unitários do DUnitX) foi executada e obteve 100% de sucesso (PASSARAM) em todas as combinações de compiladores e provedores assíncronos no Windows:

  • Delphi 10 Seattle (Default, Default+Radix, HttpSys, HttpSys+Radix, IOCP, IOCP+Radix) -> 100% Passaram
  • Delphi 11 Alexandria (Default, Default+Radix, HttpSys, HttpSys+Radix, IOCP, IOCP+Radix) -> 100% Passaram
  • Delphi 12 Athens (Default, Default+Radix, HttpSys, HttpSys+Radix, IOCP, IOCP+Radix) -> 100% Passaram
  • Delphi 13 Florence (Default, Default+Radix, HttpSys, HttpSys+Radix, IOCP, IOCP+Radix) -> 100% Passaram

@regyssilveira
regyssilveira merged commit 843660c into HashLoad:master Jul 10, 2026
@regyssilveira
regyssilveira deleted the feature/global-error-handler branch July 10, 2026 01:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant