No desenvolvimento de APIs modernas e microsserviços, é muito comum nos depararmos com o seguinte cenário: você precisa expor uma API pública para consumo externo na porta 80, mas ao mesmo tempo precisa expor um painel administrativo ou endpoints de monitoramento de métricas em uma porta interna reservada (como a porta 8080).
No ecossistema Delphi e Lazarus, o Horse consolidou-se como o framework web mais popular, leve e minimalista. No entanto, historicamente o framework operava sob uma fachada central baseada em métodos de classe estáticos (singletons globais). É exatamente aqui que entra a nova e poderosa funcionalidade da arquitetura Multi-Instance.
Neste artigo, vamos explorar como o Horse foi redesenhado para suportar servidores logicamente isolados rodando concorrentemente no mesmo processo de aplicação, e entender o “pulo do gato” de infraestrutura para colocar isso de pé em produção.
O Desafio do Acoplamento Global
Até então, o registro de rotas, middlewares e ganchos de ciclo de vida (como onRequest ou onSend) era vinculado diretamente à classe global estática THorse. Se você tentasse declarar dois servidores paralelos no mesmo programa para isolar rotas internas de externas, um acabava interferindo ou sobrescrevendo as configurações do outro.
Com a introdução da classe THorseInstance, esse acoplamento global foi quebrado. Agora, todas as estruturas de roteamento, pipelines de middlewares e hooks são encapsulados dentro de objetos individuais e isolados.
Colocando a Mão na Massa: Uso Básico
A configuração de múltiplos servidores logicamente isolados é extremamente simples e intuitiva. Basta instanciar a classe THorseInstance para cada servidor que você deseja gerenciar:
program MultiInstanceConsole;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
System.Classes,
Horse;
var
FPublicApi: THorseInstance;
FAdminPanel: THorseInstance;
begin
// Desativa o bloqueio interno de console do Listen para retornar a execução imediatamente
IsConsole := False;
// 1. Configurando a API Pública (Porta 9001)
FPublicApi := THorseInstance.Create;
FPublicApi.Get('/api/v1/ping',
procedure(Req: THorseRequest; Res: THorseResponse; Next: TNextProc)
begin
Res.Send('Pong da API Pública (Porta 9001)');
end);
// 2. Configurando o Painel de Admin (Porta 9002)
FAdminPanel := THorseInstance.Create;
FAdminPanel.Get('/admin/ping',
procedure(Req: THorseRequest; Res: THorseResponse; Next: TNextProc)
begin
Res.Send('Pong da Área Administrativa (Porta 9002)');
end);
// 3. Inicializando as escutas (os sockets ativam em background e retornam instantaneamente)
FPublicApi.Listen(9001);
FAdminPanel.Listen(9002);
Writeln('Servidores inicializados.');
Writeln('Pressione [ENTER] para encerrar...');
Readln;
// 4. Parando e liberando instâncias
FPublicApi.StopListen;
FAdminPanel.StopListen;
FPublicApi.Free;
FAdminPanel.Free;
end.
Standalone Sockets vs. Servidores Web Gerenciados (O Pulo do Gato)
Um detalhe de engenharia de redes muito importante a se compreender ao programar no Horse é a diferença de escuta entre o ambiente local de testes e o servidor de produção real:
1. Modo Standalone (Indy, IOCP, HttpSys locais)
Os provedores físicos tradicionais locais do Horse operam internamente como singletons globais no sistema operacional. Por esse motivo, tentar inicializar dois listeners físicos paralelos no mesmo executável standalone de console local costuma gerar colisões de bindings de sockets ou portas no SO (como erros do tipo EIdNotASocket).
2. Modo Gerenciado (IIS/ISAPI, Apache Modules, CGI, FastCGI)
É em produção que o THorseInstance brilha em sua totalidade de uso corporativo:
- Em ambientes web gerenciados, quem escuta fisicamente nas portas externas (ex: porta
80para usuários e8080para administradores) é o próprio IIS ou Apache. - O servidor web intercepta as conexões físicas e repassa as requisições HTTP para o processo ou DLL (ISAPI) do Horse.
- O módulo central de escuta do framework (
THorseWebModule) extrai a porta em que a conexão original ocorreu a partir do cabeçalho da requisição (Request.ServerPort). - O Horse consulta dinamicamente qual instância de
THorseInstanceestá mapeada para aquela porta específica e executa a sua árvore de rotas isolada, garantindo total independência lógica de middlewares e segurança das rotas.
Compatibilidade com Lazarus e Free Pascal
Um ponto forte dessa refatoração é a manutenção do suporte multiplataforma. Como o Free Pascal (FPC 3.2.2) não oferece suporte completo a métodos anônimos e closures na mesma estrutura do Delphi, toda a estrutura interna de resolução de instâncias lógicas e roteamento foi adaptada para rodar de forma thread-safe no Lazarus usando ponteiros de métodos tradicionais, preservando a compilação pura e performance em servidores Linux.
Conclusão
A arquitetura Multi-Instance eleva o Horse a um novo patamar de maturidade corporativa no desenvolvimento de APIs Delphi e Lazarus. Ela nos permite desenhar estruturas de microsserviços muito mais limpas, organizadas e seguras, separando preocupações de endpoints administrativos, telemetria e APIs comerciais no mesmo processo lógico.
O recurso já está comitado, testado com sucesso absoluto em todas as versões do Delphi e FPC, e pronto para ser adotado nos seus novos projetos!
Gostou dessa novidade? Deixe seu comentário abaixo dizendo se você já precisou expor portas separadas nas suas APIs Delphi!
Descubra mais sobre Régys Borges da Silveira
Assine para receber nossas notícias mais recentes por e-mail.
Dê-nos sua opinião, seu comentário ajuda o site a crescer e melhorar a qualidade dos artigos.