2026-06-10_cadencia-generation-queue-4-defeitos-design-despacho¶
Incidente: generation_queue — 4 defeitos de design no despacho convergindo em blogs duplicados, carrosséis faltando e órfãs¶
Data: 10/06/2026 Severidade: Alta Projeto: Cadência Duração do impacto: desde ~abril (race condition documentada em 25/04) até 10/06; sintomas agudos no tenant Alexandre em 09/06 Tags: #backend #bd #supabase #railway #vps #schema-drift #silenciosa #regressao #conteudo
O que aconteceu¶
Investigação estruturada (/debug-polya, modo CRÍTICO) do PDL-171 revelou que os bugs recorrentes do generation_queue (PDL-470, 473, 476, 477, 478) não eram bugs isolados — eram 4 defeitos de design na mesma arquitetura de despacho:
- Aprovação = 3 dispatches fire-and-forget (
/pipeline/runRailway + insertgeneration_queue+trigger-generationVPS), todos com.catch(() => {})— erros engolidos, sem reconciliação. Na rajada de 8 swipes do tenant Alexandre (09/06 17:11), 6 chamadas ao Railway falharam silenciosamente → 6 de 8 posts sem carrossel (PDL-473). - Row de bookkeeping nascia
pendingsem consumidor — o despacho real vai por HTTP body (direct mode); a colunachannelsera write-only. Órfãs acumulavam pra sempre (PDL-470). - Cron diário (11h BRT) consumia qualquer row pending sem filtro de canal nem dedupe — pegava a órfã da aprovação e gerava o MESMO blog de novo (3 pares duplicados confirmados no tenant felipe-salgueiro: 29/05, 03/06, 08-09/06).
trigger_server.pyainda spawnava 1 thread por trigger sem lock — 8 pipelines paralelos no mesmo tenant. - Schema drift desde abril:
channeletopicexistiam em prod sem migration versionada; a migration de 02/06 (channels[]) atacou só o sintoma do insert.
Agravante: em 09/06 um agente sem supervisão "corrigiu" marcando as 9 órfãs do Alexandre como completed em lote (22:15) — destruiu a evidência sem corrigir nada e sem logar a sessão.
Causa raiz¶
A generation_queue nasceu pro carrossel Railway; o Growth foi pendurado nela em abril, gerou race condition (incidente 25/04), e o "fix" foi bypass (direct mode --idea-id) deixando a fila semanticamente quebrada. Cada sintoma posterior ganhou patch isolado; os 4 defeitos estruturais continuaram gerando bugs novos a cada semana. A prevenção do incidente de 25/04 já avisava: "qualquer pipeline VPS que dependa de generation_queue deve usar passagem direta de ID, não polling" — mas o modo fila do cron ficou ativo, sem filtro e sem dedupe.
Por que não foi detectado¶
- 3 dispatches fire-and-forget com
.catch(() => {})— nenhum erro visível no frontend - Railway/VPS logam mas não propagam; "completed" aparentava sucesso
- Duplicatas de blog só visíveis comparando
published_postsporcontent_idea_id/título - Limpezas manuais (inclusive por agente não supervisionado) mascaravam o acúmulo de órfãs
Como foi corrigido¶
Branch felipeluissalgueiro/pdl-171-fix-definitivo-generation-queue (cadencia-app) + deploy direto na VPS Master (backup .bak-20260610-2049):
generation-queue/route.ts: insert comstatus='dispatched'(registro, não fila) — mata órfãs na raiz; bônus:usePipelineStatuspara de pollar eternamenteblog_generate.py(VPS): dedupe porcontent_idea_idempublished_posts(ambos os modos) + filtrochannels=cs.%7Bblog%7Dno modo fila (URL-encoded —sb_getusa curl, que globba{})trigger_server.py(VPS):run_pipeline_locked— lock por tenant serializa pipelines do mesmo tenant- Migration
20260610210000: versionachannel/topic+ índice (aplicada em prod via Management API) - DML: 2 rows zumbis
processing(tenants showcase, crons Railway mortos no meio) →failed - Cópia
cadencia-growth/do monorepo sincronizada com a VPS (estava stale)
E2E validado em prod: dedupe SKIP em direct e queue mode; filtro de canal funcionando; cadencia-trigger.service ativo.
Prevenção¶
Checklist / regras pra evitar recorrência¶
- [ ] Consumidor de
generation_queueSEMPRE filtra canal — nunca pegar row que não é dele - [ ] Qualquer caminho novo de geração de blog preserva o dedupe por
content_idea_id - [ ] Coluna nova em prod = migration versionada no mesmo dia (critério:
pg_dump --schema-only == migrations) - [ ] Operador PostgREST com
{}viasb_get/curl: URL-encodar (%7B...%7D) — curl globba chaves - [ ] Agente que mutar dados em prod: registrar sessão (log) + issue — limpeza sem rastro destrói evidência
- [ ] Pendências estruturais de incidente (como o de 25/04) viram issue própria — bypass não fecha causa raiz
Follow-ups abertos¶
- PDL-168 — endpoint atômico approve+enqueue (mata o fire-and-forget triplo)
- PDL-167 — watchdog/cron pra rows
processing/órfãs velhas - PDL-476/477/478 — flags de bookkeeping (
linkedin_sent,newsletter_included, contagem do front) - PDL-213 — separar
cadencia-growthem repo próprio (VPS sem git é o que permitiu o drift monorepo×VPS)
Commits relacionados¶
d4c6566(cadencia-app, branch pdl-171) — fix definitivo generation_queue
Registrado via sistema de incidentes. Ver INDEX.md para histórico completo.