Pular para o conteúdo

Entrega e ledger (recibos, retry, DLQ)

Aula 3 de 97 minOperarAtualizada em 2026-10-04

Vídeo em produção

A gravação desta aula está no lote de produção. O objetivo, o exercício e a documentação já valem. Duração-alvo: 7 min.

Objetivo: Rastrear entrega até o recibo

Selo de estado: Preview (teto atual do produto) · Curso ACD-420 — Analista de IA: relatórios, alertas, anomalias e previsões · Aula 3 de 9 · Atualizado em 2026-10-04.

Objetivo#

Ao final desta aula você vai rastrear entrega até o recibo — e distinguir "enviado" de "entregue" sem adivinhar.

Vídeo#

Identificador no manifesto: acd-420-03-entrega-email-whatsapp-ledger · duração-alvo 7 min · tela do produto: /relatorios.

Roteiro de gravação (5 capítulos):

#Minutagem-alvoCapítuloTela do produto
10:00–0:45Abertura: título + selo Preview. Por que "mandei" não é "chegou", e o que um recibo resolve./relatorios/[id]
20:45–2:30A máquina de estados do recibo: queued → sent → delivered; failed + próxima tentativa; dlq no teto./relatorios/[id]
32:30–4:00Idempotência da entrega: a chave por origem/canal/destino; reenvio do mesmo artefato não cria segundo recibo./relatorios/[id]
44:00–5:45Os dois canais: e-mail (domínio verificado) e WhatsApp (Cloud API oficial, template aprovado + consentimento)./relatorios/novo
55:45–7:00Falha que retry não conserta, reprocesso e os gates humanos. Encerramento com o "faça você mesmo"./relatorios/[id]

Conteúdo#

Por que existe um recibo

Antes do ledger, a entrega era silenciosa: uma falha de e-mail morria num campo JSON do run, sem id do provedor, sem contagem de tentativas, sem fila de reprocesso. O ledger de entrega resolve isso com um recibo por envio — origem (relatório, painel ou alerta), canal, destino, estado, número de tentativas, id no provedor e a próxima tentativa quando houver.

A máquina de estados é curta e vale decorar:

código
queued ──envio ok──────────────► sent ──(confirmação do provedor)──► delivered
  │  └─falhou e vale re-tentar──► failed + próxima tentativa ──teto (3)──► dlq
  └────canal não configurado────► failed SEM próxima tentativa
EstadoSignificaO que fazer
queuedo envio foi enfileiradoesperar; recibo parado muito tempo volta ao ciclo pelo dispatcher
sento canal aceitou a mensagemnão é prova de que chegou
deliveredhouve confirmação de entregaé o único estado que significa "chegou"
failedfalhou; se tiver próxima tentativa, voltaolhar o erro antes de reprocessar
dlqesgotou as 3 execuções de envioinvestigar a causa; reprocessar não resolve sozinho

O detalhe que mais confunde na operação: canal não configurado não é falha transiente. Se não há credencial de e-mail ou de WhatsApp, o recibo vai para failed sem próxima tentativa — porque re-tentar não conserta uma variável de ambiente ausente. Já falha de rede ou erro 5xx do provedor é transiente: entra no backoff exponencial com jitter determinístico e volta até o teto de 3.

Idempotência: o mesmo artefato, um recibo

A chave de idempotência da entrega é um hash de (origem, id da origem, canal, destino e o artefato), com UNIQUE no banco servindo de ponto de serialização. Reenviar o mesmo artefato para o mesmo destino não cria um segundo recibo: a tentativa colide, recebe o recibo existente e o produto decide se o envio acontece de novo. Corrida de crons, run reprocessado, retry manual — nada disso duplica entrega.

É a mesma ideia da idempotência de alerta da Aula 4, com uma diferença: lá a chave inclui o refreshedAt do snapshot; aqui, o artefato entregue.

Onde isso aparece na tela

No detalhe do relatório (/relatorios/[id]), a coluna Entregas do Histórico de execuções resume os recibos daquela execução: "2 ok", "2 ok · 1 falha(s)" ou — quando não houve envio. É daí que você parte: a execução pode estar Sucesso e a entrega ter falhado — são duas coisas, e o relatório as separa de propósito. Por isso a sequência de diagnóstico é sempre: status da execução → recibos da entrega → canal.

Os dois canais, e o que cada um exige

E-mailWhatsApp
Canalprovedor transacionalCloud API oficial da Meta (número + conta comercial do produto)
Pré-requisitochave do provedor + remetente + domínio verificado (DKIM)credenciais da Cloud API, template aprovado e consentimento do destinatário
Sem o pré-requisitoenvio vira no-op ou faileda mensagem não sai
Fallback—gateway não-oficial, mantido apenas como fallback deprecated
EstadoPreview · entrega real NÃO MEDIDOPreview · entrega real NÃO MEDIDO

Gates humanos desta aula

O recibo real de e-mail é gate humano: o domínio de envio transacional ainda está em verificação, então em treino você vai ver o recibo e o estado, não a prova de chegada. O envio real por WhatsApp é gate humano sob allowlist. Em ambiente não produtivo, o efeito externo é barrado de propósito — e isso aparece como recusa explícita, nunca como sucesso fingido.

Exemplo Aurora

O "Semanal Aurora" roda segunda às 8h com dois destinatários: maria@example.com (e-mail) e um número consentido (WhatsApp). O histórico mostra Status: Sucesso · Entregas: 1 ok · 1 falha(s). maria abre os recibos: o do e-mail está sent com id do provedor; o do WhatsApp está failed sem próxima tentativa, com o motivo "canal não configurado". Conclusão correta: não é instabilidade, é credencial/template ausente — reprocessar não resolveria. Na semana seguinte, um 5xx do provedor de e-mail deixou o recibo failed com próxima tentativa; na terceira execução de envio ele foi para dlq, e aí sim virou investigação.

Erros comuns

ErroPor que é erro
Ler sent como "chegou"sent é "o canal aceitou"; só delivered significa entrega confirmada
Reprocessar um failed sem próxima tentativaesse estado é canal não configurado — retry não conserta ambiente
Achar que execução Sucesso garante entregasão dois eixos: o run executou, a entrega pode ter falhado
Mandar WhatsApp sem template aprovado ou sem consentimentoé o desenho de conformidade do canal oficial, não um bug
Reenviar o mesmo relatório esperando dois recibosa idempotência devolve o recibo existente
Esperar prova de chegada em treinoentrega real é NÃO MEDIDO e depende de gate humano

Faça você mesmo#

No workspace de treino Aurora Varejo (abra /relatorios no console):

  1. Abra o "Semanal Aurora" e adicione um destinatário de WhatsApp (um número de teste com DDD) além do e-mail.
  2. Execute com Executar agora e espere a linha nova no Histórico de execuções.
  3. Leia a coluna Entregas e anote quantos recibos saíram ok e quantos falharam.
  4. Para cada recibo com falha, identifique se ele tem próxima tentativa — e portanto se é transiente (vale re-tentar) ou de configuração (não vale).
  5. Reprocesse a entrega que tem próxima tentativa e acompanhe o estado mudar; confirme que o número de tentativas sobe e que o teto é 3.
  6. Reenvie o mesmo relatório para o mesmo destino e confirme que não nasce um segundo recibo.
  7. Anote qual dos dois canais, no seu ambiente, está em gate humano — e por quê.

Atenção: este exercício depende de gate — em ambiente de treino o envio externo é barrado e os recibos refletem isso. O objetivo é ler os estados corretamente, não provar chegada.

Você terminou quando você conseguir apontar, para cada recibo da última execução, o estado, o número de tentativas e se ele admite reprocesso.

Checagem rápida#

Três perguntas no final da aula, corrigidas no servidor. A aula só conta como concluída depois da checagem.

Documentação relacionada#

Capacidades ensinadas#

C08.4 · C08.6 — o selo exibido na aula é sempre o estado mais conservador entre as capacidades citadas; nada aqui é "GA".

Carregando seu progresso…