No desenvolvimento de APIs e microsserviços modernos, garantir a alta disponibilidade e a integridade dos dados durante atualizações de versão é um requisito essencial. Se você implanta suas aplicações em ambientes de contêineres (como Docker e Kubernetes) ou atrás de um balanceador de carga, certamente já enfrentou o desafio de atualizar um serviço em produção sem derrubar as conexões ativas dos usuários.
Com a nova atualização do Horse, o framework web minimalista mais popular do ecossistema Delphi e Lazarus, introduzimos o suporte nativo ao Graceful Shutdown (Desligamento Suave). Neste artigo, vamos entender como esse recurso funciona, quais são os ganhos reais para suas aplicações e como utilizá-lo na prática.
O Problema do Encerramento Abrupto
Tradicionalmente, quando encerramos um servidor de aplicação Delphi de forma abrupta (por exemplo, fechando a console ou derrubando o processo), o socket de escuta é fechado imediatamente. Isso interrompe de forma violenta qualquer transação de banco de dados ou processamento de requisição que estava rodando naquele milissegundo.
Como consequência:
- Clientes frustrados: O usuário final recebe um erro desagradável de conexão perdida (Connection Reset) ou 502 Bad Gateway do proxy reverso.
- Inconsistência de dados: Se o servidor estava salvando um pedido ou processando um pagamento, o fluxo é interrompido no meio, podendo corromper transações de banco de dados.
- Problemas de deploy: Orquestradores como o Kubernetes não conseguem atualizar as réplicas sem causar pequenas janelas de indisponibilidade aos usuários (conhecidos como downtimes de deploy).
A Solução: Como funciona o Graceful Shutdown no Horse?
O Graceful Shutdown resolve esse cenário dividindo o encerramento do servidor em quatro etapas coordenadas:
- Sinalização imediata: O servidor marca o estado global
IsShuttingDowncomo verdadeiro. Isso avisa aos endpoints de Health Check que o nó está prestes a sair do ar. - Interrupção do Listener: O socket físico que aceita novas conexões é desligado imediatamente. Nenhuma nova requisição de rede entra no servidor.
- Escoamento de conexões (Drain): O Horse aguarda cooperativamente que todas as requisições que já estavam em andamento terminem de processar e enviem as respostas de forma íntegra para os clientes.
- Timeout de segurança: Se alguma requisição pendente travar (por exemplo, um loop infinito), um timeout de segurança (configurável) garante que o servidor finalize de qualquer forma após o tempo limite, evitando processos órfãos na memória.
Como usar na Prática (Código de Exemplo)
Abaixo, temos um exemplo didático completo em Delphi demonstrando como ativar um endpoint de Health Check usando as novas telemetrias do Horse e como disparar o encerramento suave:
program ConsoleGracefulShutdown;
{$APPTYPE CONSOLE}
uses
Horse, System.SysUtils, System.Classes, Horse.Commons;
begin
// 1. Endpoint que simula uma tarefa demorada (ex: geração de PDF)
THorse.Get('/slow-process',
procedure(Req: THorseRequest; Res: THorseResponse; Next: TProc)
begin
Writeln(' -> Processamento demorado iniciado...');
TThread.Sleep(2000); // Simula 2 segundos de execução
Res.Send('Tarefa concluída com sucesso!');
end);
// 2. Endpoint de Health Check dinâmico
THorse.Get('/health',
procedure(Req: THorseRequest; Res: THorseResponse; Next: TProc)
begin
if THorse.IsShuttingDown then
begin
// Retorna status 503 para informar ao balanceador para retirar este nó de rota
Res.Send('Servidor entrando em desligamento suave.').Status(THTTPStatus.ServiceUnavailable);
end
else
begin
// Retorna status 200 detalhando o número de conexões ativas concorrentes
Res.Send(Format('Servidor saudável. Conexões ativas: %d', [THorse.ActiveRequests]));
end;
end);
THorse.OnListen :=
procedure
begin
Writeln('Servidor executando na porta ', THorse.Port);
Writeln('Pressione [ENTER] para acionar o Graceful Shutdown...');
end;
THorse.Listen(9000);
Readln; // Aguarda entrada no console para iniciar o desligamento
Writeln('Aviso de desligamento recebido. Iniciando Graceful Shutdown (Timeout: 5s)...');
// Aciona o desligamento suave dando até 5000ms para escoar os requests ativos
THorse.StopListenGraceful(5000);
Writeln('Servidor finalizado com segurança!');
end.
Integração com Kubernetes e Docker
Ao rodar sua aplicação Delphi ou Lazarus em um orquestrador como o Kubernetes, você pode configurar Probes de Readiness e Liveness apontando para a sua rota /health.
Quando o Kubernetes decidir atualizar sua aplicação para uma versão nova:
- Ele envia um sinal (como o
SIGTERM) para a sua aplicação Horse. - A sua aplicação aciona o
THorse.StopListenGracefule o status de/healthpassa a responder imediatamente503 Service Unavailable. - O Kubernetes remove o contêiner antigo das rotas de tráfego de rede imediatamente.
- Qualquer requisição que ainda estava rodando no contêiner antigo termina de ser processada e respondida com sucesso nos próximos segundos.
- Após as conexões zerarem, o processo Horse finaliza limpo, e a nova versão do seu microsserviço assume o controle sem perder uma única requisição de cliente!
Conclusão
Com essa nova funcionalidade de Desligamento Suave, o Horse dá mais um passo importante em direção a arquiteturas enterprise robustas e preparadas para nuvem (cloud-native). A resiliência de tráfego que antes exigia scripts e configurações complexas a nível de infraestrutura agora é gerenciada de forma nativa e integrada à sua aplicação Delphi ou Lazarus.
A atualização já está disponível na branch principal do projeto. Não deixe de atualizar seus serviços e se beneficiar de deploys 100% livres de downtime!
Gostou da novidade? Deixe seu comentário abaixo dizendo se você já usa o Horse em produção com contêineres!
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.