ZAP-API
PreçosCasos de UsoBlogDocsLogin
Começar grátis
  1. Blog
  2. Deploy com zero downtime: smoke test automático e rollback instantâneo
DevOps

Deploy com zero downtime: smoke test automático e rollback instantâneo

Como fazer deploy de integrações WhatsApp sem derrubar instâncias ativas: smoke test automático após deploy, rollback em segundos se algo falhar.

24 de maio de 2026·13 min de leitura·Equipe Editorial ZAP API

14h00 de uma quarta-feira. Você dá git push esperando que o deploy passe limpo, troca pra outra aba e em 90 segundos recebe a primeira mensagem no WhatsApp do cliente: "tá fora?". Em 5 minutos, 14 clientes reportaram. Em 12 minutos, suporte está em chamas. O bug? Uma migration de banco que travou 3 minutos rodando, segurou o boot do backend novo, e como o velho já tinha sido derrubado, o sistema ficou em white-screen.

Esse cenário só acontece quando o deploy é "ingênuo": derruba antigo, sobe novo, torce. Esse artigo mostra como configurar um pipeline com smoke test automático e rollback instantâneo (em segundos) que permite deploys diários sem nunca derrubar cliente — o mesmo padrão usado pela ZAP API em produção desde abril/2026.

Por que deploy ingênuo dá problema

Os 4 modos comuns de quebra silenciosa:

  • Migration que trava: ALTER TABLE em tabela grande lockou tudo. App novo nem subiu.
  • Env var faltando: .env de produção não tinha a chave nova. App sobe, mas crasha no primeiro request.
  • Build com bug não pego em CI: tipo um .env.production não inlinado direito. App sobe sem erro mas frontend chama URL errada.
  • Dependência externa morta: versão nova depende de Redis 7 mas o container ainda é Redis 6.

Em todos os casos, monitoring tradicional (uptime ping) demora 30-90s pra detectar. Cliente já viu o erro.

Arquitetura: git push → build → smoke → ativo OU rollback

O fluxo correto, em 5 etapas atomicas:

  1. Pre-deploy: salva referência do commit atual (oldrev) — esse é o ponto de rollback.
  2. Build: docker compose build com cache. Se falhar, aborta antes de tocar produção.
  3. Up: sobe containers novos com nova tag.
  4. Healthcheck + smoke test: verifica /health endpoints e roda suite de smoke (auth, envio sandbox, webhook, etc). Se passar, segue. Se falhar, dispara rollback.
  5. Rollback automático: volta para oldrev, rebuild e up dos containers antigos. Notifica time.

Hook de pre-receive no servidor

O servidor expõe um bare git em /opt/git/seuapp.git. O hook post-receive é o orquestrador.

#!/bin/bash
# /opt/git/seuapp.git/hooks/post-receive
set -e

while read oldrev newrev refname; do
  branch=$(git rev-parse --symbolic --abbrev-ref $refname)
  if [ "$branch" != "main" ]; then
    echo "Branch $branch não é main — ignorado"
    continue
  fi

  echo "=== Deploy iniciado em $(date) ==="
  echo "From: $oldrev"
  echo "To:   $newrev"

  cd /opt/apps/seuapp
  git --git-dir=/opt/git/seuapp.git --work-tree=/opt/apps/seuapp checkout -f $newrev

  # Build & up
  docker compose -f docker-compose.prod.yml build --no-cache backend
  docker compose -f docker-compose.prod.yml up -d --force-recreate backend

  # Espera healthy (max 60s)
  echo "=== Aguardando backend healthy ==="
  for i in {1..30}; do
    health=$(docker inspect --format='{{.State.Health.Status}}' meuapp_backend 2>/dev/null || echo "starting")
    if [ "$health" = "healthy" ]; then
      echo "Backend healthy em ${i}s"
      break
    fi
    sleep 2
  done

  if [ "$health" != "healthy" ]; then
    echo "ERRO: backend não ficou healthy. Disparando rollback."
    rollback "$oldrev"
    exit 1
  fi

  # Smoke test
  echo "=== Rodando smoke test ==="
  if bash /opt/apps/seuapp/scripts/smoke-test.sh; then
    echo "=== Deploy completo com sucesso ==="
  else
    echo "ERRO: smoke test falhou. Disparando rollback."
    rollback "$oldrev"
    exit 1
  fi
done

rollback() {
  local oldrev=$1
  cd /opt/apps/seuapp
  git --git-dir=/opt/git/seuapp.git --work-tree=/opt/apps/seuapp checkout -f $oldrev
  docker compose -f docker-compose.prod.yml build backend
  docker compose -f docker-compose.prod.yml up -d --force-recreate backend
  curl -X POST "$DISCORD_WEBHOOK" -d "{\"content\":\"Deploy revertido para ${oldrev:0:7}\"}"
}

Smoke test: 9 casos críticos

O smoke deve rodar em <60 segundos e cobrir os caminhos críticos. Falhe-rápido em qualquer um.

#!/bin/bash
# /opt/apps/seuapp/scripts/smoke-test.sh
set -e

BASE="http://127.0.0.1:8280"
TOKEN="${SMOKE_TEST_TOKEN}"
FAIL=0

check() {
  local name=$1
  local expected=$2
  local actual=$3
  if [ "$actual" = "$expected" ]; then
    echo "[OK] $name"
  else
    echo "[FAIL] $name (esperado $expected, recebeu $actual)"
    FAIL=1
  fi
}

# 1. Backend health
status=$(curl -s -o /dev/null -w "%{http_code}" "$BASE/health")
check "backend health" "200" "$status"

# 2. DB health
status=$(curl -s -o /dev/null -w "%{http_code}" "$BASE/health/db")
check "db health" "200" "$status"

# 3. Redis health
status=$(curl -s -o /dev/null -w "%{http_code}" "$BASE/health/redis")
check "redis health" "200" "$status"

# 4. Auth: /v1/instances sem token = 401
status=$(curl -s -o /dev/null -w "%{http_code}" "$BASE/v1/instances")
check "auth guard 401" "401" "$status"

# 5. Auth: /v1/instances com token = 200
status=$(curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $TOKEN" "$BASE/v1/instances")
check "auth com token" "200" "$status"

# 6. Frontend root carrega
status=$(curl -s -o /dev/null -w "%{http_code}" "http://127.0.0.1:3450")
check "frontend root" "200" "$status"

# 7. Frontend login carrega
status=$(curl -s -o /dev/null -w "%{http_code}" "http://127.0.0.1:3450/login")
check "frontend login" "200" "$status"

# 8. Frontend register carrega
status=$(curl -s -o /dev/null -w "%{http_code}" "http://127.0.0.1:3450/register")
check "frontend register" "200" "$status"

# 9. Envio sandbox: end-to-end real
sandbox=$(curl -s -X POST "$BASE/v1/sandbox/inst_smoke/send" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"to":"5511999999999","type":"text","text":{"body":"smoke"}}')
echo "$sandbox" | grep -q '"ok":true' && echo "[OK] sandbox send" || { echo "[FAIL] sandbox send"; FAIL=1; }

if [ $FAIL -eq 1 ]; then
  echo "=== SMOKE FALHOU ==="
  exit 1
fi
echo "=== SMOKE PASSOU (9/9) ==="

Healthcheck no docker-compose

# docker-compose.prod.yml
services:
  backend:
    image: seuapp:${TAG:-latest}
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://127.0.0.1:8280/health"]
      interval: 5s
      timeout: 3s
      retries: 6
      start_period: 30s

Sem o healthcheck, docker inspect não retorna estado de health, e o hook não tem como saber se o app realmente está pronto.

Blue-green deployment (próximo passo)

O esquema acima ainda derruba o backend antigo antes de subir o novo (~5 segundos de glitch). Pra zero downtime real:

  1. Backend roda em 2 instâncias paralelas: backend_blue (porta 8280) e backend_green (porta 8281).
  2. Nginx faz upstream apontando pra "ativo".
  3. Deploy sobe nova versão na cor inativa, roda smoke nela, e só então alterna upstream.
  4. Cor antiga fica viva 5 minutos como backup imediato — basta apontar nginx de volta.
# nginx-blue-green.conf
upstream backend_active {
  server 127.0.0.1:8280; # blue (alterna pra :8281 quando green ativo)
}

server {
  listen 443 ssl;
  server_name api.seuapp.com;
  location / {
    proxy_pass http://backend_active;
  }
}

Switch via sed -i 's/8280/8281/g' nginx-blue-green.conf && nginx -s reload. Reload é instantâneo, conexões ativas drenam graciosamente.

Monitoramento pós-deploy: 5 minutos críticos

Mesmo com smoke passando, alguns bugs só aparecem em load real. Os primeiros 5 minutos pós-deploy são monitorados intensivamente:

// Watcher pós-deploy
const start = Date.now();
const watchDuration = 5 * 60 * 1000; // 5 min

while (Date.now() - start < watchDuration) {
  const metrics = await fetchMetrics();

  if (metrics.errorRate > 0.05) {
    console.error("Error rate >5%, disparando rollback");
    await triggerRollback();
    break;
  }
  if (metrics.p95Latency > 2000) {
    console.error("P95 latency >2s, disparando rollback");
    await triggerRollback();
    break;
  }
  await sleep(15_000); // checa a cada 15s
}

Casos práticos

ZAP API (caso real)

Pipeline V2 ativo desde 27/abr/2026: 9 smoke tests, rollback automático em <30s, healthcheck 5s interval. Em ~30 deploys pós-V2, 4 disparam rollback automático e 0 cliente reportou downtime. Antes do V2 (V1 ingênuo), tínhamos média de 1 incidente/semana.

Veredicto

Pipeline similar mas com migration check separado: antes de subir backend novo, roda migration em transaction com timeout de 10s. Se travar, aborta e nada é tocado.

Estagiário fazendo deploy

Com pipeline V2 robusto, qualquer dev (incluindo estagiário) pode dar git push pra main em horário comercial. O pior caso é rollback automático em 30s — sem custo humano. Antes, deploy era ritual exclusivo do tech lead às 22h.

FAQ

Zero downtime real é possível mesmo?

Com blue-green sim — o switch de upstream do nginx é instantâneo (<100ms) e conexões ativas no backend antigo drenam até completar. Sem blue-green, você tem ~3-8s de glitch (containers reciclando), o que é aceitável pra maioria dos casos.

E se o deploy mudou schema do banco?

Migrations devem ser backward compatible: app novo deve funcionar com schema novo, app antigo deve funcionar com schema novo (rollback do app não desfaz schema). Isso quase sempre se traduz em: adicione coluna nullable, deploy app novo, depois (em deploy seguinte) remova suporte à coluna antiga.

Posso fazer rollback de migration?

Em teoria sim (down migration). Em prática raramente — dados já podem ter sido escritos. A regra é: faça migrations forward-only e backward-compatible. Rollback = reverter código, não schema.

Como fazer canary (1% dos usuários veem nova versão primeiro)?

Configure no nginx ou load balancer roteamento por hash do IP/cookie: 1% dos requests vão pra cor nova, 99% pra antiga. Se métricas da nova cor (error rate, latency) ficam dentro do esperado por 30 minutos, vira 100%. Senão, rollback. Ferramentas: Flagsmith, Unleash, ou implementação custom com Redis.

Custo extra de blue-green?

2x a memória/CPU do backend (você roda 2 instâncias permanentemente). Para um backend de 1GB RAM em droplet de R$120/mês, custo extra ~R$60/mês. Comparado ao custo de um único incidente em horário comercial (cliente cancelando, hora de eng), paga em 1-2 incidentes evitados.

Quer testar deploy seguro antes de migrar produção? A ZAP API expõe ambiente sandbox isolado para você testar pipelines, smoke tests e rollback sem risco em produção real. Criar conta grátis e ativar sandbox no painel.

Experimente a ZAP API gratuitamente

7 dias de trial sem precisar de cartão. A partir de R$29/mês*.

Criar instância grátis
EE
Equipe Editorial ZAP APIRevisão técnica

Desenvolvedores e especialistas em integrações WhatsApp. Todo conteúdo passa por revisão técnica para garantir precisão e aplicabilidade.

Ver perfil completoDocumentaçãoTrial grátis

Leia também

Tutorial · 06 de jun. de 2026 · 12 min

WhatsApp API para Atendimento Automático: guia completo 2026

Respostas fora do horário, triagem de leads por palavra-chave, fluxos condicionais e transferência para humano: como montar atendimento automático no WhatsApp em menos de 30 minutos.

Vertical · 16 de mai. de 2026 · 11 min

WhatsApp API para contadores: boleto, prazo e declaração automáticos

Como escritórios de contabilidade usam WhatsApp API para alertar clientes sobre vencimentos, solicitar documentos e enviar guias de recolhimento automaticamente.

Observabilidade · 21 de mai. de 2026 · 12 min

Endpoint de diagnóstico: monitorar instâncias WhatsApp sem SSH

Use o endpoint de diagnóstico da ZAP API para consultar métricas de saúde, alertas e performance de instâncias WhatsApp via HTTP, sem precisar de acesso SSH ao servidor.

Arquitetura · 19 de mai. de 2026 · 13 min

Rate limiting em WhatsApp API: throttle inteligente por sessão

Implemente rate limiting inteligente para disparos WhatsApp: throttle dinâmico por número, janelas deslizantes e backoff automático para evitar banimento.

Tópicos:Chatbots com IAE-commerceAPI WhatsApp

Explore também

Casos de usoWhatsApp API por segmentoComparativoZAP API vs alternativasPreçosPlanos e o que está inclusoGlossárioTermos técnicos de WhatsApp API
ZAP-API

API REST para WhatsApp com webhooks assinados, Meta Pixel/CAPI e compliance LGPD. Sem aprovação da Meta.

Status operacional🇧🇷 Feito no Brasil

Produto

  • Preços
  • Casos de uso
  • Comparativo
  • Trial grátis
  • Dashboard

Recursos

  • Documentação
  • Blog
  • Glossário
  • RSS Feed

Empresa

  • Sobre
  • Imprensa
  • Termos de uso
  • Privacidade
  • Criar conta
  • Login

Contato

  • [email protected]
  • [email protected]
  • Resposta em até 24h úteis
© 2026 ZAP-API — Todos os direitos reservados·CNPJ 42.130.949/0001-56·Termos·Privacidade

Desenvolvido por PreviusIA