Por que uma integração "funciona" em demonstrações e falha silenciosamente em produção
Em um teste de aceitação padrão, enviamos uma única mensagem, confirmamos seu recebimento e a aprovamos. Em produção, a mesma integração processa milhares de mensagens por dia, e algumas delas falharão – devido a timeouts, bloqueios de linha, autorizações expiradas ou mudanças de esquema no outro sistema. A questão crucial que determina a qualidade da solução não é "a integração está funcionando?", mas sim "o que acontece quando ela não funciona, e quem percebe?".
A maioria das falhas custosas que observei não decorreu de um bug no código da integração em si, mas da ausência de três capacidades: a identificação de que uma mensagem falhou, um mecanismo que tenta novamente sem criar duplicatas, e um processo que garante que a informação em ambos os sistemas esteja de fato consistente no final do dia. Sem isso, qualquer integração "funciona" até o momento em que se descobre que ela não funciona há duas semanas.
As quatro camadas que compõem o tratamento adequado de erros
| Camada | O que ela resolve | Falha típica sem ela |
|---|---|---|
| Idempotência | A reexecução da mesma mensagem não cria um registro duplicado | Pedido duplicado ou movimento de estoque duplicado após a Retentativa |
| Retentativa com Backoff | Falha temporária (Timeout, Rate Limit) é corrigida automaticamente | Carga inesperada momentânea se torna um problema persistente |
| Dead Letter Queue | Falha não temporária é sinalizada e não desaparece silenciosamente | Mensagem é "engolida" e as partes envolvidas pensam que foi processada |
| Reconciliação de Negócios | Lacunas de dados que não foram explicitamente identificadas são reveladas | Relatório mensal revela uma inconsistência cuja origem é difícil de rastrear |
Cada camada depende da anterior. Uma retentativa sem idempotência cria duplicatas; uma Dead Letter sem reconciliação esconde o fato de que, mesmo mensagens "tecnicamente" bem-sucedidas, não necessariamente refletem a situação de negócios correta.
Idempotência: A chave para prevenir duplicação
Toda integração que pode receber a mesma mensagem mais de uma vez – e quase todas as integrações se enquadram nessa categoria – precisa de um identificador externo único (External ID) que identifique o evento, e não apenas o registro. No Salesforce, a implementação comum é um Upsert por meio de um campo External ID com restrição de unicidade, combinado com uma tabela de log (Custom Object ou Platform Event Log) que registra quais identificadores de evento já foram completamente processados.
O erro comum: contentar-se com um Upsert no próprio registro de negócio (por exemplo, Order External ID) sem documentar os estágios intermediários. Se o processo também envolve a atualização de estoque em um sistema externo, um Upsert na ordem não impede uma repetição de chamada para a atualização de estoque – cada suboperação com um efeito colateral externo (Side Effect) deve ser idempotente por si só, não apenas o registro final.
Retentativa: Política de Backoff e Classificação de Erros
Nem todo erro merece uma retentativa. É preciso separar previamente três categorias:
- Erros Temporários (Timeout, 503, Rate Limit) – Candidatos a retentativa com Exponential Backoff, ou seja, o intervalo entre as tentativas aumenta (por exemplo, 30 segundos, 2 minutos, 10 minutos) para não agravar a carga.
- Erros Estruturais (campo obrigatório ausente, violação de Validation Rule, valor inválido) – Não devem ser retentados, pois falharão novamente da mesma forma. Eles precisam ser direcionados diretamente para a Dead Letter.
- Erros de Autorização ou Configuração (Token expirado, mudança de API Version) – Exigem notificação imediata à equipe técnica, pois bloqueiam toda a fila e não apenas uma única mensagem.
No Salesforce, a implementação de retentativa geralmente é feita na camada do Middleware ou em Apex Queueable/Batch com um contador de tentativas armazenado no próprio registro. Um número razoável de tentativas para a maioria dos casos é de 3-5 com Backoff, não uma retentativa infinita – uma retentativa sem limite transforma uma falha temporária em uma carga contínua para ambos os sistemas.
Dead Letter Queue: Onde as mensagens com falha "vivem"
Uma Dead Letter não é apenas um local de armazenamento; é um contrato. Cada mensagem que chega até ela deve conter: identificador de evento original, Payload completo, motivo de falha classificado, número de tentativas realizadas e tempo de entrada na fila. Sem essas informações, o "tratamento" de uma Dead Letter se torna um exercício de adivinhação.
Duas abordagens comuns para implementação no Salesforce:
- Custom Object dedicado (
Integration_Failed_Message__c) com campos estruturados e List View por tipo de erro – adequado quando a equipe de negócios precisa de visibilidade dentro do próprio Salesforce. - Fila externa na camada de Middleware (por exemplo, Dead Letter Exchange no MuleSoft/Boomi) – adequado quando a equipe técnica monitora externamente ao Salesforce e deseja evitar sobrecarga na Org.
A escolha depende de quem deve agir sobre a falha: se for o proprietário do processo de negócio, ele precisa ver isso dentro do Salesforce; se for a equipe técnica de integração, é preferível na camada externa.
Reconciliação de Negócios: O teste que revela o que a retentativa não detectou
Mesmo com idempotência e retentativa perfeitas, existem falhas que "são bem-sucedidas" do ponto de vista técnico, mas criam uma lacuna de negócios – por exemplo, uma mensagem que foi recebida e processada, mas com um valor incorreto proveniente de uma fonte de dados desatualizada. A reconciliação é um processo periódico (diário, horário, dependendo da frequência dos eventos) que compara uma contagem ou um somatório acumulado entre os dois sistemas – por exemplo, o número de pedidos criados no ERP versus o número de pedidos criados no Salesforce para o mesmo dia – e destaca as diferenças antes que se tornem um problema de serviço ao cliente.
Um bom processo de reconciliação não exige uma verificação campo por campo de cada registro; uma soma de verificação (Checksum) ou uma contagem acumulada que sinaliza quando é preciso detalhar é suficiente. Na maioria das organizações, uma frequência diária é suficiente; em processos financeiros ou críticos (pedidos, faturamento), é necessária uma verificação em poucas horas.
Decision Framework: Quando cada camada é obrigatória e quando pode ser dispensada
| Critério | Idempotência Obrigatória | Retentativa Automática Obrigatória | Dead Letter Separada Obrigatória | Reconciliação Diária Obrigatória |
|---|---|---|---|---|
| O evento cria movimento financeiro ou de estoque | Sim | Sim | Sim | Sim |
| O evento é unidirecional, apenas leitura (Read) | Não crítico | Sim | Não | Não |
| Volume acima de 500 mensagens por dia | Sim | Sim | Sim | Recomendado |
| Parceiro externo sem SLA de alta disponibilidade | Sim | Sim, com Backoff longo | Sim | Recomendado |
| Integração entre dois objetos não financeiros de baixo volume | Recomendado | Recomendado | Não essencial | Não |
A regra que orienta a tabela: quanto maior o impacto financeiro ou irreversível de uma falha (envio, faturamento, atualização de estoque), todas as quatro camadas passam de "desejável" para "obrigatória" – independentemente do volume.
Cenário de Exemplo: Varejista com sincronização de pedidos bidirecional
Uma empresa varejista com 40 filiais utiliza o Salesforce para gerenciar pedidos B2B e um ERP externo para estoque e faturas. A integração foi construída originalmente com uma chamada REST simples: quando um pedido é criado no Salesforce, uma chamada síncrona o cria no ERP. Sem retentativa, sem Dead Letter.
Durante um período de alta demanda (Black Friday), o ERP começou a retornar Timeout em cerca de 3% das chamadas. Sem um mecanismo de retentativa, esses 3% simplesmente "desapareceram" – o pedido permaneceu no Salesforce com status "enviado" sem que o ERP soubesse dele. Em dois dias, acumularam-se cerca de 140 pedidos que não chegaram ao processo de empacotamento, e foram descobertos apenas quando os clientes ligaram para perguntar sobre o paradeiro da mercadoria.
A solução desenvolvida subsequentemente: uma camada Queueable no Apex que tenta novamente até 5 vezes com Backoff de 1/5/15/30/60 minutos; um campo ERP_Sync_Status__c com valores Pending/Synced/Failed; um Custom Object Integration_Failed_Message__c que centraliza as falhas finais com um botão "Processar Novamente" para a equipe de operações; e um relatório de reconciliação diária que compara a contagem de pedidos entre os sistemas e envia um alerta no Slack quando a diferença excede zero. O tempo de detecção de uma falha semelhante diminuiu de dois dias para menos de uma hora.
Riscos Comuns e Ações Preventivas
| Risco | Como se manifesta na prática | Ação Preventiva |
|---|---|---|
| Retentativa infinita de erros estruturais | A mesma mensagem falha repetidamente, gerando carga | Classificar erros previamente e enviar erros estruturais diretamente para a Dead Letter |
| Ausência de um identificador único de evento | Retentativas ou chamadas duplicadas criam registros duplicados | External ID no evento, não apenas no registro final |
| Dead Letter sem Proprietário | Mensagens se acumulam e ninguém as resolve | Definir Proprietário e SLA de tratamento por tipo de evento, não por sistema |
| Monitoramento apenas técnico (status de API) | A integração está "verde", mas os dados de negócio não estão alinhados | Adicionar Reconciliação que compare o resultado de negócio, não apenas o código de resposta |
| Backoff fixo e muito curto | Tentativas repetidas agravam a carga durante uma falha generalizada | Exponential Backoff com um limite de tentativas definido |
Checklist antes da aprovação do design de tratamento de erros
- ☐ Cada evento possui um identificador único (External ID) que impede duplicidade em reexecuções
- ☐ Erros são classificados previamente em temporários/estruturais/autorização, com tratamento distinto para cada tipo
- ☐ Uma política de Backoff é definida com um número máximo de tentativas
- ☐ Existe uma Dead Letter acessível com Payload completo e motivo de falha
- ☐ Há um Proprietário e um SLA de tratamento definidos para cada tipo de falha
- ☐ Existe um processo de Reconciliação periódico que compara o resultado de negócio entre os sistemas
- ☐ Alertas chegam a um canal onde alguém realmente os lê (não apenas para logs)
- ☐ O cenário de teste inclui a interrupção do serviço do outro sistema, não apenas o Happy Path
Como isso se conecta ao restante da arquitetura
O design do tratamento de erros não é um recurso isolado – ele se apoia na camada de dados e permissões definida no Guia de Arquitetura de CRM, e na decisão se a lógica é implementada em Flow ou Apex, conforme Salesforce Flow ou Apex. O modelo de permissões pelo qual os componentes de integração escrevem dados deve ser verificado em relação ao Modelo de Permissões do Salesforce, para que um usuário técnico da integração não obtenha acesso excessivamente amplo. E à medida que o volume de mensagens aumenta, a questão da retentativa se encontra diretamente com as limitações de API detalhadas em Limites de API do Salesforce.
Conclusão
O tratamento de erros de integração não é um recurso a ser adicionado no final – é a diferença entre um sistema que se revela quebrado depois que um cliente reclamou, e um sistema que se alerta antes que o dano se acumule. As quatro camadas – Idempotência, Retentativa classificada, Dead Letter com Proprietário, e Reconciliação de Negócios – não exigem um projeto separado, mas demandam uma decisão explícita na fase de planejamento, antes que a primeira integração entre em produção. Uma organização que se alerta sobre 3% de mensagens com falha em uma hora é fundamentalmente diferente de uma organização que descobre isso por um cliente insatisfeito.
