0009 — Watchdog do heartbeat do CSV do X-Adm¶
Status: Aprovado · Responsável: Gustavo Madruga · Atualizado em: 2026-09-12 · Decidido em: 2026-08-07
Contexto¶
O X-Adm posta o catálogo (ProdutosSite.csv em .zip) no tradutor (POST /api/csv/processar) em
ciclos regulares (a cada ~60 min) dentro do horário comercial. Se essa rotina parar (falha no
X-Adm, agendador caído, rede), o e-commerce do parceiro passa a servir preço/estoque velhos e
ninguém percebe — não há sinal de "faz X minutos que não chega nada". Faltava um watchdog que
transformasse o silêncio do X-Adm num alarme.
Decisão¶
Um watchdog @Scheduled (Monitor + MonitorScheduler, pacote …webstormecom.monitor) que, dentro
da janela útil, alarma no GlitchTip se ficar mais que timeout-alarme minutos sem receber CSV:
- Heartbeat =
webstorm_ecom_ingestao(o últimocreated_at): a chegada do CSV. Um snapshot que chega com erros ainda conta como "recebido" — o watchdog vigia silêncio do X-Adm, não a qualidade do dado. - Janela útil
[janela-inicio, janela-fim)no fusozona(default 07h–20h America/Sao_Paulo): fora dela o silêncio é esperado → nunca alarma (e desarma um alarme pendente). Na abertura, a referência de idade é a abertura de hoje (não o último de ontem) — assim as 07h não disparam falso alarme. - Edge-triggered: alarma uma vez na transição (uma linha
ERROR→ GlitchTip pela recipe dologback.xml), não spamma; desarma quando chega dado novo; re-alarma se estourar de novo. - Config
webstorm.monitor.*(yaml/env):periodicidade(60),timeout-alarme(240),intervalodo check (5m),janela-inicio/janela-fim(07:00/20:00),zona. Validação no boot (fail-fast, estiloApiTokenGuard):timeout-alarme ≥ 2 × periodicidadee janela não-vazia — senão o app não sobe. - Estado in-memory (
volatile Instant alarmadoDesde): sem tabela nova. Um deploy durante um silêncio na janela re-alarma uma vez (a condição ainda é real) — aceito. - Tela read-only
/admin/monitor(MonitorViewController): periodicidade, timeout, janela+zona, último recebido, idade, e o estado (OK / fora-da-janela / ALARMADO desde). Sob aViewSecurityRuledo app (login@xadm.com.br, com bypass dev/test — é tela própria, não a rule da lib mensageria).
Notas de implementação (armadilhas de stack)¶
SELECT max(created_at)→Optional<Instant>, nuncaInstant. Num agregado nulável, tabela vazia devolve NULL, e o Micronaut Data com retorno não-Optionallança"Query produced no result"em runtime — que aqui seria 500 no watchdog num deploy novo, antes do 1º CSV (bug pego por teste de tabela-vazia).IngestaoRepository.ultimoRecebido()éOptional<Instant>.- Horários no YAML como literais entre aspas (
"07:00"), não${ENV:07:00}: o:do horário confunde o parser de default de placeholder do Micronaut (${K:07:00}quebra no último:e resolve"00"), e07:00sem aspas viraria sexagesimal no YAML. Trade-off: a janela deixou de ser env-configurável (muda-se editando o yaml + redeploy) — aceitável (raramente muda). - Testabilidade: a decisão é uma função pura
Monitor.avaliar(agora, zona, janela, ultimo, alarmadoDesde, timeout)— testada sem relógio/banco; oMonitorScheduler(@Requiresnowebstorm.monitor.enabled) só faz o wiring e é desligado nos ITs (padrão doSweepScheduler).
Fica de fora (follow-up se exigido)¶
- Edição dos valores pela tela / persistência do estado — decisão: yaml + in-memory (a tela é read-only). Tabela editável seria over-engineering pra agora.
- Calendário de dias úteis/feriados — a janela vale todo dia; se o X-Adm não enviar fim de semana/feriado, sábado 07h+timeout alarmaria falso. Precisaria de calendário (não neste escopo). Dias da semana resolvidos na atualização de 2026-09-12 (abaixo); feriados seguem de fora.
- Outro canal de alarme além do GlitchTip (o
SentryAppenderjá existente).
Consequências¶
- O silêncio do X-Adm vira um alarme observável no GlitchTip; o operador confirma o estado em
/admin/monitor. - Novos knobs de deploy
MONITOR_*/WEBSTORM_MONITOR_ENABLED(ver implantação §5.2).
Alternativas descartadas¶
- Alarmar 24/7 (sem janela) — falso alarme toda madrugada, quando o X-Adm legitimamente não envia.
- Config em tabela editável pela tela — runtime sem redeploy, mas migração + form + CSRF + validação no save sem necessidade presente (a janela/timeout raramente mudam).
- Persistir o estado alarmado — evita o re-alarme de 1× no deploy, ao custo de uma tabela para um booleano; o re-alarme é inócuo (a condição é real).
Atualização 2026-09-12 — dias da semana vigiados¶
Sábado 2026-09-12 o watchdog alarmou às 11:02 (242 min sem CSV desde a abertura das 07:00). O alarme
era verdadeiro — o X-Adm costuma enviar no fim de semana (13–14 CSVs em 15/08, 16/08, 29/08, 30/08 e
06/09, medido na webstorm_ecom_ingestao) e naquele sábado não enviou nada —, mas silêncio de fim de
semana não deve acionar ninguém.
- Nova config
webstorm.monitor.dias(envMONITOR_DIAS), siglas pt-br separadas por vírgula, defaultSEG,TER,QUA,QUI,SEX. Dia fora da lista vale como fora da janela: não alarma e desarma um alarme pendente (oemJanelaagora é dia e horário). - Segunda-feira usa a mesma regra da virada do dia: a referência é a abertura de segunda (07:00), não o último CSV da sexta. Uma queda que começa no sábado só alarma segunda ~11:00 (07:00 + 240 min) — aceito: é o custo de não acionar ninguém no fim de semana.
- Fail-fast no boot: lista vazia ou sigla desconhecida (ex.
MON,SEXTA) derruba o app, como a validação detimeout-alarme. Parse sem diferenciar maiúscula nem acento (sáb=SAB). - A tela
/admin/monitormostra os dias vigiados. - Feriados seguem fora de escopo (precisariam de calendário).
Linhagem de trabalho: .ia/011-watchdog-heartbeat-csv-*.