Zero-downtime deploy: por que isso é crítico para o seu serviço JavaScript?
\n\nImagine: sexta-feira, noite, você faz deploy de uma nova funcionalidade em Node.js — e em um minuto o chat de suporte técnico recebe mensagens de pânico: "O site caiu!", "Erro 500!", "Dados perdidos!". Familiar? Se o seu serviço JavaScript para de responder durante a atualização — você perde não apenas usuários, mas também dinheiro e reputação.
\n\nZero-downtime deploy (implantação sem interrupções) — é uma abordagem onde a atualização do código ocorre de forma imperceptível para o usuário. Todas as requisições são processadas, as conexões não são interrompidas e o novo código entra em operação suavemente. Para Node.js, onde tudo depende de assincronia e eventos, isso é especialmente importante: uma interrupção brusca pode causar vazamentos de memória ou promises não tratadas.
\n\nNeste artigo, mostrarei como configurar o deploy contínuo de serviços JavaScript na prática. Vamos analisar três estratégias funcionais — Rolling Update, Blue-Green Deployment e Graceful Shutdown — com exemplos reais de código. Vamos lá!
\n\nEstratégia 1: Rolling Update — atualização sem parada
\n\nRolling update (atualização gradual) — é a técnica mais popular no mundo Node.js. A ideia é simples: você tem várias instâncias da aplicação rodando e as atualiza uma por uma. Enquanto uma reinicia, as outras continuam recebendo tráfego.
\n\nComo funciona na prática
\nSuponha que você tenha 4 processos Node.js rodando via PM2 (um gerenciador de processos popular). O comando pm2 reload app automaticamente faz um rolling restart: mata um processo por vez e inicia o novo código. Mas para que isso funcione sem erros, é necessário configurar corretamente o graceful shutdown (mais sobre isso abaixo).
Exemplo de configuração do PM2 para zero-downtime
\nCrie um arquivo ecosystem.config.js na raiz do projeto:
module.exports = {\n apps: [{\n name: 'my-javascript-service',\n script: './server.js',\n instances: 4, // 4 instâncias\n exec_mode: 'cluster', // modo cluster\n wait_ready: true, // aguarda sinal ready\n listen_timeout: 5000, // timeout para prontidão\n kill_timeout: 5000, // timeout para encerramento\n max_restarts: 10,\n env: {\n NODE_ENV: 'production'\n }\n }]\n};\n\n\nE no código do servidor (server.js), adicione o tratamento de sinais:
const http = require('http');\nconst app = require('./app'); // sua aplicação Express/Koa\n\nconst server = http.createServer(app);\nconst PORT = process.env.PORT || 3000;\n\nserver.listen(PORT, () => {\n console.log(`Servidor rodando na porta ${PORT}`);\n // Envia sinal ao PM2 de que o processo está pronto\n if (process.send) {\n process.send('ready');\n }\n});\n\n// Graceful shutdown\nprocess.on('SIGINT', () => {\n console.log('SIGINT recebido, iniciando graceful shutdown...');\n server.close(() => {\n console.log('Servidor HTTP fechado');\n process.exit(0);\n });\n});\n\nprocess.on('SIGTERM', () => {\n console.log('SIGTERM recebido, encerrando...');\n server.close(() => {\n console.log('Servidor HTTP fechado');\n process.exit(0);\n });\n});\n\n\nAgora, ao executar pm2 reload ecosystem.config.js, o PM2 irá parar e iniciar as instâncias uma por uma, aguardando o sinal ready. Os usuários não perceberão a troca.
Prós e contras do Rolling Update
\n- \n
- + Não requer servidores ou proxies adicionais. \n
- + Fácil de configurar via PM2 ou Kubernetes. \n
- - Se o novo código contiver um erro crítico, a instância "ruim" pode processar algumas requisições antes de ser detectada. \n
- - Requer gerenciamento cuidadoso de estado (banco de dados, cache). \n
Estratégia 2: Blue-Green Deployment — dois ambientes sem risco
\n\n
Blogs
Book Recommendations
Leia também