Pipeline de mensagens — fluxos e cenários
Doc canônico do pipeline de mensagens com 7 cenários (sucesso, retry-success, retry-DLQ, retry-manual, 4xx não-retentável, cert-expirando, cancelar). Estados, classifier de erros, onde ver tudo.
Visão geral do pipeline
[parceiro/SAP] → POST /api/mapeamentos/receive-message ou /api/webhook/[id]
↓
[insert messages com pipeline_status='received']
↓
[processMessage síncrono em src/lib/pipeline/process-message.ts]
├─ duplicate check (por message_type)
├─ map (se há mapping configurado)
└─ send (se há connection destino)
├─ sucesso → pipeline_status='sent' / dest_status='200'
└─ falha → pipeline_status='error' / dest_status_text=erro
↓
[tryEnqueueRetry em src/lib/queue/retry-orchestrator.ts]
├─ retry_auto_enabled=false → fica em 'error' (usuário)
├─ erro não retentável → fica em 'error'
├─ retry_count<max → 'retry_pending' + job em job_queue
└─ esgotou → 'dead_letter' (se DLQ on) ou 'error'
O worker
/api/cron/process-queue puxa jobs prontos da job_queue (RPC dequeue_jobs com FOR UPDATE SKIP LOCKED) e re-executa processMessage pra cada um. Em nova falha, chama tryEnqueueRetry de novo. Se a tentativa agendada é interrompida (o worker cai no meio e o reaper fecha o job, ou a gravação fica sem resposta), ela conta como tentativa e a política decide de novo — a mensagem não fica em retry_pending sem job. A rede de segurança (requeue-stalled-messages, a cada 10 min) recolhe o retry órfão que ainda sobrar: retry_pending vencida há mais de 15 min, sem job, fora de lote de envio e da fila de trabalho → error com o registro na linha do tempo, e a política decide. A Idempotency-Key do envio (REST, OData e webhook) leva a revisão do documento (nexio-<mensagem>-r<instante da leitura>): o retry da mesma revisão repete a chave e o destino deduplica; a revisão nova do documento usa chave nova e não é descartada como duplicata. Resultado do envio incerto (timeout ou reset depois de enviar, 502/504, job do bridge já assumido, lote sem resposta): o destino pode ter recebido. A CONEXÃO de destino (REST ou webhook) escolhe, em "Quando o resultado do envio for incerto": reenviar com a chave de idempotência (padrão, o comportamento de sempre; arrisca duplicar se o destino não honra a chave — marque "O destino honra a Idempotency-Key" só quando confirmado), consultar o destino (REST: caminho, campo da resposta com a referência e, opcional, atraso de consistência; só conta como entregue com 2xx E a referência no corpo; sem prova vai para conferência) ou conferência humana (error com dest_status = delivery_uncertain, classe DELIVERY_UNCERTAIN, não retentável; reprocesso em massa e leitura completa não reenviam; reprocessar uma mensagem exige a confirmação explícita de reenvio). A conferência de "entregou e não gravou" usa como início da tentativa o maior entre o último job e messages.revision_at (a releitura do documento): a entrega da revisão anterior não conta. A exceção DEPOIS do 2xx do destino grava delivered_unrecorded na hora (não MAPPING_ERROR nem erro de envio retentável); se o sent já estava gravado, fica como está. Resposta que não chega (timeout, reset) segue retentável, protegida só pela chave de idempotência do conector. Se a tentativa interrompida registrou a entrega (message_deliveries sent depois do início dela) e só o desfecho não foi gravado, nada reenvia: error com dest_status = delivered_unrecorded (classe DELIVERED_UNRECORDED), para conferir no destino. Worker morto entre o HTTP e qualquer gravação: pelo menos uma vez, como received.Estados de pipeline_status
| Status | Significado | Próximo passo |
|---|---|---|
received | Mensagem entrou no banco; processMessage ainda não rodou | Pipeline executa |
mapped | Field mapping aplicado, aguardando envio | sendToDestination |
sent | Entregue ao destino com sucesso | Final |
error | Falhou ou esgotou retries (sem DLQ) | Humano clica reprocessar |
retry_pending | Falhou mas retry automático agendado | Worker pega no run_after |
dead_letter | Esgotou retries com DLQ habilitado | Alerta + revisão manual em /admin/queue |
cancelled | Humano cancelou retry em vôo | Final |
received_observed | Modo observability — recebeu mas não enviou | Final (modo monitor) |
7 cenários de execução
Cenário A — Sucesso direto
Mensagem entra, mapeia, envia, destino retorna 200.
pipeline_status: received → mapped → sentdest_status: "200"- Webhook event
message.senté disparado pra integrações de saída - Logs em
message_logsstep=sentstatus=success
Cenário B — Erro 5xx + retry automático ON + sucesso na 2ª tentativa
Integração com
retry_auto_enabled=true, destino retorna 503.- 1ª tentativa:
pipeline_status: received → error(dest='503') tryEnqueueRetryclassificahttp_5xx(retryable), calculanextRetryAt(ex: +60s exponential), atualiza:
pipeline_status: 'retry_pending'
- retry_count: 1
- next_retry_at: now+60s
- last_retry_error_class: 'http_5xx'
- Job inserido em
job_queuecomrun_after=now+60s - Worker executa, processMessage funciona desta vez →
pipeline_status: 'sent'
Cenário C — Erro 5xx + retry automático ON + esgota tentativas → DLQ
Mesmo cenário B, mas todas as N tentativas falham.
- Tentativas 1..retry_max:
retry_pendingcom backoff (30s, 60s, 120s, ...) - Após retry_max:
tryEnqueueRetryretornaexhausted_dlq - Se
retry_dead_letter=true:pipeline_status='dead_letter' - Senão: fica em
'error' - Cron
/api/cron/dlq-alertsagrupa por integração + bucket horário, dispara Slack e email praRESEND_NOTIFY_EMAIL - Aparece em
/admin/queueaba "Dead-letter" com botões "Reprocessar" e "Cancelar"
Cenário D — Retry automático OFF (default) → fica parado pro usuário
Integração com
retry_auto_enabled=false (o padrão de produto).- Falha →
pipeline_status: 'error'(sem retry, sem job na fila) - Mensagem fica visível no monitor
- Operador clica "Reprocessar" →
/api/mapeamentos/reprocess-messagereseta status e re-executa pipeline - Se reprocessar manual também falha, mesmo fluxo: ou volta pro usuário (auto OFF) ou enfileira retry (auto ON)
Cenário E — Erro 4xx (payload inválido) → não retenta nunca
Destino retorna 400/403/404/422 — problema do payload, não transiente.
tryEnqueueRetryclassifica comohttp_4xxousyntaxretryable=false— independente de retry_auto_enabled, não enfileira- Atualiza apenas
last_retry_error_class - Mensagem fica em
errorpro usuário corrigir o mapping/payload - 401 é exceção: classificado como
http_401retryable (token pode ter renovado) - 429 também: classificado como
rate_limited, parseiaRetry-Afterdo response
Cenário F — Certificado digital expirando (alerta proativo)
Não é fluxo de mensagem, mas afeta integrações que usam mTLS (SEFAZ, etc).
- Cron
/api/cron/cert-expiry-alertsroda 07:00 UTC - Varre
connections.certificates.client.not_after - Buckets: 30, 14, 7, 1 e 0 dias
- 1 alerta por bucket via Slack (config
SLACK_ALERTS_WEBHOOK_URL) - UI: integration-card mostra badge "Cert vence em Xd" amarelo (≤30d) ou vermelho (≤7d)
- Renovação automática: trigger
connections_cert_expiry_alerts_resetapaga rows antigas quandonot_aftermuda — buckets resetam sozinhos
Cenário G — Operador cancela retry em vôo
Mensagem em
retry_pending (ex: retry_count=2 of 5), usuário decide parar.- Em
/admin/queueaba "Aguardando" ou "Dead-letter", botão X (cancelar) - POST
/api/admin/messages/[id]/cancel-retry:
job_queue (started_at IS NULL)-
pipeline_status: 'cancelled'
- next_retry_at: null
- Audit event message.retry_cancelled registrado
- Worker eventual nunca executa o job (porque já foi removido)
Cenário H — Modo observability (read-only)
Integração com
mode='observability' — default pra novos tenants.- Mensagem chega via webhook/API →
processMessageroda normal - Mapping aplica (se configurado) →
pipeline_status: 'mapped' - Antes de chamar
sendToDestination, helperskipSendintercepta:
pipeline_status: 'received_observed'
- dest_status: 'skipped_observability'
- dest_status_text: 'Modo observability — envio ao destino bloqueado'
- Log step=observability registrado- Não chama
sendData — destino do cliente fica intocado
tryEnqueueRetryno-op (não há erro pra retentar; mensagem foi observada com sucesso)- Card da integração mostra badge READ-ONLY azul persistente
Use pra: rollout enterprise progressivo. Cliente roda Lefia em paralelo com iPaaS atual sem risco de duplicar dado. Quando confiar, alterna pra
orchestration no edit da integração — UI esconde retry policy enquanto observability (irrelevante).Cenário I — Reentrega exata bloqueada (idempotency)
Parceiro reenvia exatamente o mesmo payload (timeout, falha de rede do lado dele).
Camadas de proteção (do mais cedo pro mais tarde):
- Header HTTP
Idempotency-Key— se cliente passou (Stripe-style)
sanitizeIdempotencyKey (RFC: ASCII printable, ≤255 chars)- UNIQUE INDEX
(tenant_id, integration_id, idempotency_key)
- Bate → retorna mensagem original sem reinserir, response com deduplicated: true, deduplicated_by: 'idempotency_key'
- Fingerprint computada — sempre, mesmo sem header
(message_type_id + duplicate_key_fields normalizados + hash payload canônico)
- Reaproveita os duplicate_key_fields da UI "Tratamento de Duplicatas"- UNIQUE INDEX
(tenant_id, integration_id, fingerprint)
- Bate → retorna original com deduplicated_by: 'fingerprint'
- Race-condition fallback — se 2 requests concorrentes passaram pelo pré-check
23505 (unique violation) — handler busca o winner e devolve com deduplicated_by: 'race_winner'Distinção importante: idempotency NÃO substitui a UI "Tratamento de Duplicatas" (
duplicate_handling por message_type). Eles cobrem cenários diferentes:
- Idempotency: mesmo payload byte-a-byte (reentrega exata)
- duplicate_handling: mesmas chaves de negócio mas conteúdo distinto (ex: 2 PO-12345 com itens diferentes — operador decide accept/reject/overwrite)
Idempotency atua antes do INSERT; duplicate_handling atua dentro do
processMessage depois de inserir.Onde ver o que
| O que | Onde |
|---|---|
| Mensagens em retry, jobs pendentes, DLQ | /admin/queue (super_admin) |
| Toggle de retry automático por integração | Edit da integração → seção "Política de Retry" |
| Janela de horário (afeta retry) | Edit da integração → seção "Agendamento" |
| Histórico de logs por mensagem | /mapeamentos/integracao/[id] |
| Erros do Lefia em si (não de integração) | /admin/errors + Sentry |
| Alertas Slack | canal configurado em SLACK_ALERTS_WEBHOOK_URL |
| Email de DLQ | RESEND_NOTIFY_EMAIL |
Plataforma SEFAZ — caso especial
Em "Plataforma" do form de criar/editar integração, escolher SEFAZ automaticamente:
- Troca o protocolo pra SOAP (webservice nativo)
- Mostra hint "SEFAZ exige mTLS — anexe o certificado digital A1 (.pfx/.p12)"
- Campos
clientCertPfx(file upload) eclientCertPasswordficam visíveis - Server-side: parseia PKCS#12, valida senha, encripta blob+senha (AES-256-GCM), grava em
connections.certificates
Erros mapeados pelo classifier
src/lib/integrations/retry-policy.ts → classifyError():| Sinal | Classe | Retentável? |
|---|---|---|
| HTTP 5xx | http_5xx | sim |
| HTTP 429 + Retry-After | rate_limited | sim (respeita header) |
| HTTP 401 | http_401 | sim (uma vez, token pode renovar) |
| HTTP 422 | syntax | NÃO (payload/schema inválido) |
| HTTP 4xx outros | http_4xx | NÃO |
| ETIMEDOUT, msg "timeout" | timeout | sim |
| ECONNRESET, ECONNREFUSED, ENOTFOUND | connection | sim |
| msg com "schema/parse/invalid xml" | syntax | NÃO |
| outros | unknown | sim (default seguro) |
Privacidade no retry
- Cert digital: blob e senha sempre encriptados em repouso (
src/lib/crypto.tsAES-256-GCM) - Payload da mensagem: redaction de PII aplicada antes de qualquer chamada à IA do Lefia (
src/lib/ai/redaction.ts) — vide help articlepii-redaction-llm - Logs de retry: apenas classe do erro + dest_status_text (texto do destino), sem credenciais
Limitações conhecidas (deste commit)
- Schedule do worker
/api/cron/process-queueé diário em Vercel Hobby. Pra retries com delay < 24h o operador precisa cron externo (cron-job.org bate comBearer CRON_SECRET) ou subir pra Vercel Pro (cron a cada 1min). - Idempotency em mensagens de integração não é universal — backlog #60.
- A3 (token físico) não suportado — backlog (precisa Lefia Agent on-prem).
- Validação CRL/OCSP/cadeia não é feita no upload do cert (delegada à contraparte).
- Logging não-estruturado (Pino) — backlog #59.
Limite de taxa do destino (HTTP 429)
Quando o destino recusa por excesso de requisições, a mensagem fica com a categoria Limite de taxa do destino. O arquivo está certo: o retry automático tenta de novo e espera o tempo que o destino pediu no cabeçalho Retry-After (o mesmo vale para o 503 com Retry-After), até o intervalo máximo de retry configurado na integração. Se o destino pedir mais do que isso, a tentativa sai no intervalo máximo e a linha do tempo da mensagem avisa. Se continuar, aumente o intervalo das tentativas ou reduza as execuções em paralelo da integração.
Tentativas com o destino fora do ar
Na tela da mensagem, Tentativas mostra quantas vezes a entrega foi tentada dentro do limite de tentativas da integração e, entre parênteses, os reenvios feitos enquanto o destino estava fora do ar, que não contam nesse limite (por exemplo, "3 tentativas (+5 sem contar durante queda do destino)"). Enquanto o destino estiver fora, a tela diz desde quando e até quando as novas tentativas não contam. Reprocessar a mensagem zera essa contagem.
Histórico de versões
- 1.14.0
Destino fora do ar: a mensagem enviada sozinha (fora do lote) passa a ter a mesma proteção do lote. Quando é certo que nada saiu — falha no login do destino, conexão que nem abriu, ou erro 5xx com o destino confirmado fora pela sonda — ela é reenviada por tempo, sem gastar tentativa, até a janela da conexão ("Destino fora do ar: tentar por até (minutos)", padrão 60), e a conexão pausa para as outras mensagens esperarem. Tempo esgotado depois de enviar (pode ter chegado) e o erro de um destino que está respondendo continuam com o número de tentativas da integração. Antes essa regra existia só atrás de uma chave desligada.
21/10/2026 · updated
- 1.13.0
Reenvio automático do lote que falhou porque o destino ficou fora do ar por mais que a janela de envio em lote. Para a conexão que declara que o destino honra a Idempotency-Key, quando o destino volta e um envio dá certo, o lote que tinha falhado de vez pela janela volta sozinho, um por vez, o mais antigo primeiro, com a mesma chave de idempotência (o destino que a honra não duplica) e uma única vez por lote. Não voltam sozinhos: lote que falhou por erro de conteúdo ou lote envenenado, resultado incerto que foi para conferência, integração com retry desligado, em observabilidade ou com tentativas zero, e conexão que não declarou a idempotência (esses seguem pelo Reprocessar lote). O Reprocessar lote continua valendo e cancela o reenvio automático daquele lote.
18/10/2026 · updated
- 1.12.0
Novas tentativas e reprocesso mais seguros contra envio em dobro. Reprocessar uma mensagem (ou um lote) enquanto a entrega dela está no meio do envio agora espera essa entrega terminar, em vez de mandar de novo. A nova tentativa automática também espera a fila de trabalho que ainda vai processar a mensagem. Na criação de documentos no SAP (OData), uma falha no login do destino passa a ser tratada como "nada foi enviado": a mensagem volta a tentar sozinha em vez de parar para conferência. A tela da mensagem mostra as tentativas contadas e, à parte, os reenvios feitos enquanto o destino estava fora do ar, que não contam no limite da integração.
18/10/2026 · updated
- 1.11.1
Fim do envio em dobro entre o envio imediato e a fila. Na entrega enfileirada, o Lefia tenta enviar a mensagem logo depois de responder ao remetente, e a fila fica como rede de segurança. Antes, se o envio imediato demorasse (por exemplo, um login lento no destino), a fila podia enviar a mesma mensagem ao mesmo tempo e o parceiro recebia duas vezes. Agora o envio imediato só sai depois de assumir a entrega na fila; se a fila já assumiu, ele desiste. Se o envio imediato for interrompido, a fila retoma a mesma entrega depois de 15 minutos. Uma falha do destino no envio imediato segue a política de novas tentativas da integração, como na fila.
17/10/2026 · updated
- 1.11.0
Destino fora do ar também no LOGIN e na mensagem enviada sozinha. Quando o login do destino (usuário e senha que devolvem um token, ou a troca de token OAuth) responde com erro passageiro — 5xx (como o 508 da plataforma), 408, 425, 429, tempo esgotado ou falha de rede/DNS — a entrega trata como destino fora do ar: o lote espera a pausa automática e é reenviado sem gastar tentativa até a janela da conexão passar ("Destino fora do ar: tentar por até (minutos)", padrão 60). Credencial recusada no login (401, 403 e os outros 4xx do login) continua erro, sem nova tentativa, na categoria Autenticação. Para a mensagem que vai sozinha (fora do lote) a mesma regra existe atrás de uma chave por ambiente, desligada por enquanto (toda tentativa avulsa conta); quando ligada, vale quando é certo que nada saiu (falha no login, conexão que nem abriu, ou o 5xx com o destino confirmado fora pela sonda): ela é reenviada por tempo sem gastar tentativa e a conexão pausa para as outras esperarem; tempo esgotado depois de enviar (pode ter chegado) e o erro 500 de um destino que está respondendo — ou de um conector sem sonda — continuam com o número de tentativas da integração. O registro da entrega guarda os cabeçalhos de diagnóstico da resposta de erro (ex.: x-vercel-error), que dizem se o erro veio da plataforma do destino ou da aplicação.
17/10/2026 · updated
- 1.10.2
Correções na entrega: o retry automático não agenda mais uma mensagem que tem uma entrega enfileirada aberta (a checagem agora é refeita no banco, sob a trava da mensagem, e não só antes de chamá-lo), o que evita enviar a mesma mensagem duas vezes. E a sonda do destino com certificado do cliente (mTLS) deixa de dizer "destino fora" quando o servidor derruba a conexão depois do aperto de mão, que é como o TLS 1.3 pode recusar o certificado: o aviso passa a apontar o certificado e o envio real decide.
17/10/2026 · updated
- 1.10.1
Correção na entrega em lote: quando a gravação que põe a mensagem na espera do lote falha (por exemplo, por uma trava momentânea do banco), a mensagem não fica mais parada em "Recebida" sem ninguém cuidar dela — a decisão é refeita, ou a mensagem vai para erro com nova tentativa automática (marcada como falha do Lefia, não do destino). O mesmo vale para a entrega enfileirada e a adiada pela contrapressão, e a entrega enfileirada nunca envia o documento de origem sem mapear quando a integração tem mapeamento: sem o mapeado gravado, a mensagem vai para erro e é decidida de novo. E a sonda que testa o destino depois de uma pausa passou a entender destinos atrás de API gateway: 401, 403, 404 e 405 do gateway e o redirecionamento para a página de login contam como destino no ar (o redirecionamento não é seguido); 502, 503 e 504 do gateway contam como destino fora. Problema de certificado ou de TLS não é tratado como queda (o envio real decide e mostra o erro), e a conexão que cai no meio do aperto de mão TLS conta como destino fora.
16/10/2026 · updated
- 1.10.0
Envio em lote resiliente à queda do destino. Com o destino fora do ar (erro 5xx, tempo esgotado, conexão recusada), o lote não gasta tentativa: ele espera e é reenviado até a janela da conexão passar (padrão 60 min, campo novo "Destino fora do ar: tentar por até (minutos)"). A conexão pausa já no primeiro lote em falha; depois da pausa, uma sonda leve (consulta sem envio) testa o destino e o lote só sai inteiro quando o destino responde. Erro de conteúdo (4xx) e o 5xx de um destino que está respondendo continuam com o número de tentativas da integração. Lote que falha de vez (a janela passou) volta pelo Reprocessar lote, com a mesma chave de idempotência; o orçamento de tentativas recomeça. O lote guarda os cabeçalhos de diagnóstico da resposta de erro (ex.: x-vercel-error), que dizem se o erro veio da plataforma do destino ou da aplicação.
15/10/2026 · updated
- 1.9.1
Pausa automática do destino que cai, revisada: só pausa quando lotes DIFERENTES da conexão falham (a partir de 2) por indisponibilidade do destino (erro 5xx, tempo esgotado, conexão recusada ou DNS), sem nenhum envio bom no meio. Um lote só com erro repetido (conteúdo inválido) não para a conexão. A tela, o aviso de pausa longa e o texto do adiamento passam a dizer que a pausa é automática, não um pedido do destino.
14/10/2026 · updated
- 1.9.0
Envio em lote: quando o destino devolve erro 5xx várias vezes seguidas (sem pedir espera), a conexão faz uma pausa automática crescente (30 s até 5 min, respeitando o Retry-After do destino) e retoma sozinha; os lotes esperam sem gastar tentativa e saem com a mesma chave de idempotência (nada duplica). O reenvio de um lote que falhou com 5xx nunca espera menos de 30 s.
14/10/2026 · updated
- 1.8.0
Correção do envio em lote: um lote aceito e confirmado pelo destino não deixa mais mensagens com o status "enviando". O lote só é montado com mensagens cujo processamento terminou, o envio e a confirmação gravam o lote e as mensagens juntos, e uma verificação periódica acerta qualquer lote cujo estado diverge do das mensagens (inclusive agendando a consulta da confirmação que faltou).
10/10/2026 · updated
- 1.7.0
Correção: em destinos que confirmam a entrega por consulta, uma mensagem enviada cuja consulta de confirmação não chegou a ser agendada (por exemplo, a fila ficou indisponível no instante do envio) deixa de ficar aguardando confirmação para sempre. Uma verificação periódica agenda a consulta que faltou, no máximo uma vez a cada 30 minutos, e as mensagens que dependiam dela seguem quando o destino confirma.
10/10/2026 · updated
- 1.6.0
Refinamento da opção "consultar o destino" quando o resultado do envio é incerto: se o documento já foi entregue antes numa versão anterior, a consulta não é usada (iria achar a versão antiga) e a mensagem vai para conferência; a mensagem já fica marcada para conferência antes de esperar a resposta do destino, então nada é reenviado se o processo for interrompido; e conexões de tipos que não usam chave de idempotência, como o RFC, não oferecem mais o reenvio automático nesse caso.
10/10/2026 · updated
- 1.5.0
Correção: quando um documento é alterado na origem e reenviado, destinos que respeitam a chave de idempotência (Idempotency-Key) não descartam mais a versão nova como se fosse repetição da anterior. A chave agora muda a cada versão do documento e continua a mesma nos reenvios da mesma versão, então a proteção contra envio duplicado segue valendo.
10/10/2026 · updated
- 1.4.0
Nova opção em cada conexão de destino REST ou webhook: "Quando o resultado do envio for incerto (timeout depois de enviar)". Quando o envio termina sem resposta (tempo esgotado ou conexão derrubada depois de enviar, erro 502 ou 504 do gateway, job do bridge SAP já assumido, lote sem resposta), a conexão escolhe entre reenviar com a chave de idempotência (o padrão, que é o comportamento de sempre), consultar o destino para saber se o documento chegou, ou mandar para conferência humana. A consulta só confirma a entrega com resposta de sucesso que traga a referência da mensagem. Nada muda nas conexões existentes até alguém escolher outra opção. A tela explica o risco de cada escolha.
10/10/2026 · updated
- 1.3.0
Correção de segurança de entrega: quando o destino confirma o recebimento (resposta 2xx) e depois o sistema não consegue gravar o resultado (por exemplo, o banco fica indisponível por um instante), a mensagem agora vai para conferência — "Entregue ao destino sem o desfecho gravado" — em vez de ser marcada como erro e reenviada sozinha, o que duplicaria o documento no destino. Quando a resposta do destino não chega (tempo esgotado, conexão derrubada), o reenvio continua como antes, protegido pela chave de idempotência do destino. Também corrigido: quando o documento é alterado na origem e a nova versão falha antes de ser enviada, o reenvio automático segue normalmente; a entrega da versão anterior não faz a mensagem ir para conferência por engano.
10/10/2026 · updated
- 1.2.0
O worker da fila deixa de processar um número fixo de jobs por ciclo. Ele trabalha em rodadas enquanto houver trabalho pronto, tempo sobrando no ciclo e nenhum sinal de freio (jobs adiados ou falhando em massa). As mensagens retidas por dependência e as recolhidas pela rede de segurança voltam a andar na velocidade do ciclo, não a 10 por minuto, sem aumentar a concorrência contra o destino.
10/10/2026 · updated
- 1.1.0
Correção: uma mensagem com nova tentativa agendada não fica mais parada em "aguardando retry" quando essa tentativa é interrompida (por exemplo, o processamento cai no meio). A tentativa interrompida conta como tentativa e a mensagem segue a política de retry da integração — nova tentativa, fila de mensagens mortas ou erro —, e uma verificação periódica recolhe a que ainda assim ficar sem tentativa agendada, com o registro na linha do tempo da mensagem. Mensagens de um lote de envio continuam com o retry do próprio lote. Se a tentativa interrompida chegou a entregar ao destino e só o desfecho não foi gravado, ela não é reenviada: a mensagem fica em erro com o aviso "entregue ao destino, mas o desfecho não foi gravado", para conferir no destino e reprocessar só se faltar.
09/10/2026 · updated
- 1.0.0
Retry worker com fila durável em Postgres. Default retry MANUAL; integração liga "retry automático" explicitamente. Classifier 5xx/timeout/conn retentáveis vs 4xx/syntax não. Backoff fixed/linear/exp com cap. Janela horária respeitada. DLQ com alerta Slack+email agregado por integração+hour_bucket. UI /admin/queue. Cancel-retry com audit. SEFAZ→SOAP default + hint mTLS no form. 7 cenários documentados em help.
06/05/2026 · new