fix: zero-downtime deploy com start-first e healthcheck
- Remove docker service update --force que causava downtime - Agrupa env vars do Convex em um único update (evita múltiplos restarts) - Adiciona delay: 10s e monitor: 30s no update_config - Healthcheck do web usa /api/health com timeout - Ajusta start_period: 180s (web) e 60s (convex) - Convex backend não é mais forçado a reiniciar após stack deploy Fluxo correto de deploy: 1. docker stack deploy detecta mudança 2. Novo container é criado (start-first) 3. Swarm espera healthcheck passar 4. Swarm espera monitor period (30s) 5. Container antigo é removido 6. Zero downtime durante todo o processo 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
d8936899ee
commit
40e2c01abd
2 changed files with 35 additions and 19 deletions
26
.github/workflows/ci-cd-web-desktop.yml
vendored
26
.github/workflows/ci-cd-web-desktop.yml
vendored
|
|
@ -296,26 +296,31 @@ jobs:
|
||||||
echo "Using APP_DIR (stable)=$APP_DIR_STABLE"
|
echo "Using APP_DIR (stable)=$APP_DIR_STABLE"
|
||||||
APP_DIR="$APP_DIR_STABLE" RELEASE_SHA=${{ github.sha }} docker stack deploy --with-registry-auth -c stack.yml sistema
|
APP_DIR="$APP_DIR_STABLE" RELEASE_SHA=${{ github.sha }} docker stack deploy --with-registry-auth -c stack.yml sistema
|
||||||
|
|
||||||
- name: Ensure Convex service envs and restart
|
- name: Ensure Convex service envs (sem force restart)
|
||||||
run: |
|
run: |
|
||||||
cd "$EFFECTIVE_APP_DIR"
|
cd "$EFFECTIVE_APP_DIR"
|
||||||
set -o allexport
|
set -o allexport
|
||||||
if [ -f .env ]; then . ./.env; fi
|
if [ -f .env ]; then . ./.env; fi
|
||||||
set +o allexport
|
set +o allexport
|
||||||
echo "Ensuring Convex envs on service: sistema_convex_backend"
|
echo "Ensuring Convex envs on service: sistema_convex_backend"
|
||||||
|
# Acumula todas as env vars em um único update para evitar múltiplos restarts
|
||||||
|
UPDATE_ARGS=""
|
||||||
if [ -n "${MACHINE_PROVISIONING_SECRET:-}" ]; then
|
if [ -n "${MACHINE_PROVISIONING_SECRET:-}" ]; then
|
||||||
docker service update --env-add MACHINE_PROVISIONING_SECRET="${MACHINE_PROVISIONING_SECRET}" sistema_convex_backend || true
|
UPDATE_ARGS="$UPDATE_ARGS --env-add MACHINE_PROVISIONING_SECRET=${MACHINE_PROVISIONING_SECRET}"
|
||||||
fi
|
fi
|
||||||
if [ -n "${MACHINE_TOKEN_TTL_MS:-}" ]; then
|
if [ -n "${MACHINE_TOKEN_TTL_MS:-}" ]; then
|
||||||
docker service update --env-add MACHINE_TOKEN_TTL_MS="${MACHINE_TOKEN_TTL_MS}" sistema_convex_backend || true
|
UPDATE_ARGS="$UPDATE_ARGS --env-add MACHINE_TOKEN_TTL_MS=${MACHINE_TOKEN_TTL_MS}"
|
||||||
fi
|
fi
|
||||||
if [ -n "${FLEET_SYNC_SECRET:-}" ]; then
|
if [ -n "${FLEET_SYNC_SECRET:-}" ]; then
|
||||||
docker service update --env-add FLEET_SYNC_SECRET="${FLEET_SYNC_SECRET}" sistema_convex_backend || true
|
UPDATE_ARGS="$UPDATE_ARGS --env-add FLEET_SYNC_SECRET=${FLEET_SYNC_SECRET}"
|
||||||
|
fi
|
||||||
|
if [ -n "$UPDATE_ARGS" ]; then
|
||||||
|
echo "Applying env updates (will respect update_config.order: start-first)..."
|
||||||
|
docker service update $UPDATE_ARGS sistema_convex_backend || true
|
||||||
fi
|
fi
|
||||||
echo "Current envs:"
|
echo "Current envs:"
|
||||||
docker service inspect sistema_convex_backend --format '{{range .Spec.TaskTemplate.ContainerSpec.Env}}{{println .}}{{end}}' || true
|
docker service inspect sistema_convex_backend --format '{{range .Spec.TaskTemplate.ContainerSpec.Env}}{{println .}}{{end}}' || true
|
||||||
echo "Forcing service restart..."
|
# NÃO fazemos --force aqui para respeitar a estratégia start-first do stack.yml
|
||||||
docker service update --force sistema_convex_backend || true
|
|
||||||
|
|
||||||
- name: Smoke test — register + heartbeat
|
- name: Smoke test — register + heartbeat
|
||||||
run: |
|
run: |
|
||||||
|
|
@ -375,10 +380,11 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
docker service update --force sistema_web
|
docker service update --force sistema_web
|
||||||
|
|
||||||
- name: Restart Convex backend service (optional)
|
# Comentado: o stack deploy já atualiza os serviços com update_config.order: start-first
|
||||||
run: |
|
# Forçar update aqui causa downtime porque ignora a estratégia de rolling update
|
||||||
# Fail the job if the convex backend cannot restart
|
# - name: Restart Convex backend service (optional)
|
||||||
docker service update --force sistema_convex_backend
|
# run: |
|
||||||
|
# docker service update --force sistema_convex_backend
|
||||||
|
|
||||||
convex_deploy:
|
convex_deploy:
|
||||||
name: Deploy Convex functions
|
name: Deploy Convex functions
|
||||||
|
|
|
||||||
26
stack.yml
26
stack.yml
|
|
@ -45,6 +45,10 @@ services:
|
||||||
# start-first evita downtime: sobe o novo task antes de parar o anterior
|
# start-first evita downtime: sobe o novo task antes de parar o anterior
|
||||||
order: start-first
|
order: start-first
|
||||||
failure_action: rollback
|
failure_action: rollback
|
||||||
|
# Delay entre updates para garantir que o healthcheck passa
|
||||||
|
delay: 10s
|
||||||
|
# Monitor: tempo que o Swarm espera após o deploy para verificar estabilidade
|
||||||
|
monitor: 30s
|
||||||
rollback_config:
|
rollback_config:
|
||||||
order: start-first
|
order: start-first
|
||||||
resources:
|
resources:
|
||||||
|
|
@ -66,11 +70,14 @@ services:
|
||||||
networks:
|
networks:
|
||||||
- traefik_public
|
- traefik_public
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "node", "-e", "fetch('http://localhost:3000').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
|
# Healthcheck mais robusto: verifica se o servidor responde
|
||||||
|
test: ["CMD", "node", "-e", "fetch('http://localhost:3000/api/health',{timeout:2000}).then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
|
||||||
interval: 10s
|
interval: 10s
|
||||||
timeout: 3s
|
timeout: 5s
|
||||||
retries: 5
|
retries: 3
|
||||||
start_period: 120s
|
# start_period: tempo de inicialização antes de começar a contar falhas
|
||||||
|
# O novo container só entra em serviço APÓS passar no healthcheck
|
||||||
|
start_period: 180s
|
||||||
|
|
||||||
convex_backend:
|
convex_backend:
|
||||||
image: sistema_convex_backend:1.29.2
|
image: sistema_convex_backend:1.29.2
|
||||||
|
|
@ -96,6 +103,9 @@ services:
|
||||||
parallelism: 1
|
parallelism: 1
|
||||||
order: start-first
|
order: start-first
|
||||||
failure_action: rollback
|
failure_action: rollback
|
||||||
|
# Delay e monitor para garantir zero-downtime
|
||||||
|
delay: 10s
|
||||||
|
monitor: 30s
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
# Limite de memória elevado para evitar reinícios por OOM (exit code 137) em cargas de relatórios / índices.
|
# Limite de memória elevado para evitar reinícios por OOM (exit code 137) em cargas de relatórios / índices.
|
||||||
|
|
@ -119,10 +129,10 @@ services:
|
||||||
- traefik_public
|
- traefik_public
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "curl -sf http://localhost:3210/version >/dev/null || exit 1"]
|
test: ["CMD-SHELL", "curl -sf http://localhost:3210/version >/dev/null || exit 1"]
|
||||||
interval: 30s
|
interval: 15s
|
||||||
timeout: 10s
|
timeout: 5s
|
||||||
retries: 10
|
retries: 3
|
||||||
start_period: 120s
|
start_period: 60s
|
||||||
|
|
||||||
convex_dashboard:
|
convex_dashboard:
|
||||||
image: ghcr.io/get-convex/convex-dashboard:latest
|
image: ghcr.io/get-convex/convex-dashboard:latest
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue