Runbook de incidentes comuns (runtime)¶
Status: Aprovado · Responsável: Gustavo Madruga · Atualizado em: 2026-09-10
Primeiros passos para sintomas de produção (não build/deploy — isso está em
diagnóstico de builds flaky). Observabilidade: todo ERROR
vai ao Sentry/GlitchTip (SentryAppender no logback.xml) — o dashboard é o primeiro lugar a
olhar. Erros de API saem em RFC 7807 (application/problem+json); o code/detail do corpo
ajudam a identificar a causa.
Push FCM não chega ao app¶
Ordem de verificação:
- A instância está com a empresa certa? Cada instância roda com
push.empresa(sulplata|onpetrotrading) e envia nos tópicosbl_liberado_<empresa>enota_venda_emitida_<empresa>. O app precisa estar inscrito no tópico dessa empresa. - Push está ligado?
push.enabled=truee as credenciais Firebase presentes (PUSH_CREDENTIALS_PATH→ o secret file montado no container). Compush.enabled=truee a credencial ilegível a instância não sobe — o erro de startup nomeia o path (decisão 0030), então "push mudo com a instância no ar" nunca é credencial faltando. Compush.enabled=falseo serviço é no-op silencioso. - Testar sem esperar um evento real:
POST /debug/send-bl-liberado(tela/debug, login-gated) dispara um push de teste ao tópico da instância. Se o teste chega e o real não, o problema é no gatilho (o PUT XADM não chegou / origem errada), não no FCM. - Falha de envio? O
FcmPushServicereenvia erros transitórios do FCM (INTERNAL500,UNAVAILABLE503,QUOTA_EXCEEDED) com backoff exponencial + jitter (default 3 tentativas, base 1 s → ~1 s / 2 s / 4 s). Um 500 isolado é reabsorvido no retry e não vira alarme. O Sentry/GlitchTip só recebe a exceção quando: (a) esgotam as tentativas de um erro transitório, ou (b) o erro é permanente (UNREGISTERED,INVALID_ARGUMENT,SENDER_ID_MISMATCH,THIRD_PARTY_AUTH_ERROR) — que falha de imediato, sem retry. Tags no evento:push.topic/push.tipo/push.error_code/push.attemptse os extraspush.title/push.body.push.attempts=3(o default) num evento transitório = outage do FCM, não blip. Ajustável viapush.retry.max-attempts/push.retry.base-delay-ms.
Detalhe do payload e do gatilho: push FCM · testar push.
PowerSync: app não recebe atualizações (dessincronizado)¶
O runbook dedicado cobre reset e operação: Runbook PowerSync. Checklist rápido antes:
- O serviço PowerSync está no ar? Ver PowerSync via Docker.
- As sync rules estão atualizadas para o schema atual? Ver atualizar sync rules.
- O
last-changeavança? O endpoint/api/v1/powersync/lastchangereflete a última mudança aplicada; se ele avança mas o app não recebe, o problema é do lado PowerSync/cliente. - Caso extremo (cliente com estado corrompido): o reset está no Runbook PowerSync.
Erros 500 / exceções em produção¶
- Sentry/GlitchTip primeiro — todo
ERRORé capturado; o stack trace e o contexto estão lá. - A resposta HTTP de erro sai em RFC 7807 (
application/problem+json): ocodee odetailidentificam o tipo (validação, rota inexistente,HttpStatusException). - Ingestão XADM (
PUT/DELETE /api/v1/xadm) falhando: o corpoXadmResponsetraz o resultado por entidade; um 400 é erro de cliente (JSON malformado / dado inválido) — o agente on-premises deve parar e notificar, não re-tentar.
Heartbeat do integrador-client¶
O integrador-client manda o heartbeat para POST /api/v1/heartbeat e esta instância o repassa ao
central-backend (contrato). Os dois ERRORs abaixo são
misconfiguração: não se curam sozinhos e repetem a cada heartbeat (até 1 por hora), agrupados numa
issue do GlitchTip.
ERROR heartbeat desligado: <ENV> vazio neste integrador-server (resposta 503
heartbeat_desligado). A env nomeada no log (CENTRAL_API_TOKEN, CLIENTE_ID ou as duas) está vazia
no recurso Coolify. Desde a decisão 0029, o
CLIENTE_ID vazio só derruba o heartbeat quando o COOLIFY_FQDN também não serve (fora do
formato int.<slug>.xadm.biz) — a linha cliente_id do heartbeat: no boot diz qual fonte valeu.
Cadastrar e fazer redeploy — checklist em
implantação. Se esta instância não deveria ter
integrador-client, quem está mandando heartbeat é um jar instalado por engano: desligar lá
(heartbeat.intervaloMinutos=0).
ERROR heartbeat recusado pelo central-backend: HTTP <status> [<code>] (resposta 502
heartbeat_recusado). O central devolveu 4xx. Pelo code:
| No log | Causa | Correção |
|---|---|---|
HTTP 422 cliente_desconhecido |
CLIENTE_ID não existe em clientes no central (é o cliente_id, ex. maxsul — não o CLIENTE) |
corrigir o CLIENTE_ID |
HTTP 401 invalid_token / missing_token |
CENTRAL_API_TOKEN diferente do cadastrado no central |
alinhar o valor com os recursos do central |
HTTP 400 BAD_REQUEST |
o client mandou dado que passou aqui e o central recusou (ex. iniciado_em malformado — só o central o valida) |
ver a versão do client instalada |
HTTP 404 sem code |
CENTRAL_URL aponta para o lugar errado (o proxy responde HTML) |
corrigir ou apagar o CENTRAL_URL (o default é o central de produção) |
WARN heartbeat não repassado: central-backend … (resposta 502 central_indisponivel). Central
fora, lento ou rede: transitório, fica em WARN de propósito e não abre issue. O próximo heartbeat tenta
de novo. Se durar horas, o próprio central acusa silêncio da instalação depois de 6h úteis — o runbook
do lado de lá é o
heartbeat do integrador-client no central.
Build/deploy falha (não é runtime)¶
Ver diagnóstico de builds flaky — o que a suíte instrumenta e como ler
a falha do job gate.