Voltar ao blog Conectividade

Chaves de idempotência em uma API de SMS: como evitar duplicidades em novas tentativas e timeouts

Uma chave de idempotência pode ajudar a controlar as novas tentativas de uma solicitação HTTP, mas somente se a API definir seu escopo e comportamento. Saiba o que combinar antes de repetir um envio e como separar a aceitação da solicitação do status de entrega.

Diagrama de integração de SMS que mostra uma chave de idempotência, novas tentativas HTTP e consulta do status da mensagem

Que problema a idempotência resolve no envio de SMS

Um cliente pode enviar uma solicitação HTTP e perder a conexão antes de receber a resposta. Nesse momento, não sabe necessariamente se o servidor processou a solicitação. Se repetir às cegas um envio que a API trata como uma nova operação, pode provocar uma segunda aceitação e, potencialmente, uma mensagem duplicada.

Uma chave de idempotência é um mecanismo que uma API pode oferecer para reconhecer que várias solicitações correspondem à mesma operação. Sua utilidade depende do contrato específico dessa API: o padrão HTTP não define, por si só, uma chave de idempotência nem regras para um endpoint de envio de SMS.

  • Objetivo: evitar que uma nova tentativa da mesma operação seja interpretada como uma nova solicitação.
  • Limite: evitar uma aceitação duplicada não equivale a garantir que a mensagem seja entregue uma única vez.
  • Antes de implementar novas tentativas, verifique na documentação da API se ela aceita chaves, qual é o escopo delas e que resposta retorna quando são reutilizadas.
Que problema a idempotência resolve no envio de SMS

Repetir uma solicitação HTTP nem sempre significa repetir o mesmo envio

A semântica HTTP distingue métodos idempotentes de não idempotentes. De acordo com a RFC 9110, uma operação é idempotente quando realizar várias solicitações idênticas tem o mesmo efeito previsto no servidor que realizar apenas uma. A especificação identifica métodos como PUT e DELETE; POST não é classificado como idempotente por padrão.

Por isso, não se deve presumir que reenviar um POST de envio de SMS é seguro. Se a conexão for interrompida antes da resposta, o cliente pode não saber se a solicitação foi executada. A RFC 9110 recomenda não repetir automaticamente uma operação não idempotente, a menos que se saiba que sua semântica é idempotente ou seja possível determinar que a solicitação original não foi aplicada.

  • Um timeout descreve o que o cliente observou, não necessariamente o que aconteceu no servidor.
  • Uma rejeição recebida é diferente de uma resposta perdida: se a API retornou uma resposta, use o código e o contrato dela para decidir o próximo passo.
  • Não transforme todos os erros HTTP, fechamentos de conexão ou timeouts em um reenvio automático.
Repetir uma solicitação HTTP nem sempre significa repetir o mesmo envio

Gere uma chave estável para cada operação de negócio

A chave deve identificar uma operação lógica que o sistema consiga reconhecer em todas as tentativas, por exemplo, uma solicitação de OTP associada a um evento interno específico. Se uma nova chave for gerada a cada tentativa, a API não terá um identificador comum para relacionar as solicitações.

A chave não deve incluir dados pessoais ou segredos desnecessários. Defina como gerá-la e armazená-la no seu sistema e evite reutilizá-la em outra operação. As fontes disponíveis não determinam o método exato de geração, o formato ou a entropia das chaves: isso deve ser acordado com base na documentação da API e nos requisitos de segurança da integração.

  • Atribua uma chave ao criar a operação de negócio, antes da primeira tentativa HTTP.
  • Mantenha a mesma chave nas novas tentativas dessa operação.
  • Crie uma chave diferente para uma nova operação, mesmo que o destinatário e o conteúdo sejam os mesmos.
  • Não inclua credenciais, tokens nem informações pessoais sem necessidade.

Defina o escopo e a duração antes de depender da chave

Uma chave só é inequívoca dentro do escopo definido pela API. O contrato deve esclarecer se ela é interpretada por conta, endpoint, operação ou outra combinação, além de indicar por quanto tempo a associação entre a chave e a solicitação é mantida. Não existe uma duração universal estabelecida para APIs de SMS.

Se o cliente repetir a solicitação depois que a API deixar de manter a chave, o servidor poderá tratá-la como uma nova operação. Portanto, o período de retenção deve cobrir o intervalo em que seu sistema talvez precise recuperar uma resposta perdida, e a aplicação precisa saber o que fazer quando esse período terminar.

  • Confirme o escopo de unicidade da chave e não presuma que ela seja global.
  • Documente o período de retenção e o comportamento após seu vencimento.
  • Alinhe o período de novas tentativas do cliente à retenção prevista no contrato.
  • Se a API não documentar esses pontos, peça esclarecimentos antes de automatizar reenvios.

Combine o que acontece se a chave for repetida com outro payload

Reutilizar uma chave com dados diferentes é um caso crítico. O contrato deve especificar como a API compara as solicitações e o que acontece quando a mesma chave é recebida com um payload incompatível. Uma política prudente é não reutilizar a chave para alterar o destinatário, o conteúdo ou outros campos que modifiquem a operação; a resposta específica ao conflito deve ser verificada na documentação do serviço.

Também é importante saber qual resultado o cliente recebe ao repetir exatamente a mesma solicitação. Algumas APIs podem retornar um resultado associado à primeira operação, mas não há evidências disponíveis para afirmar que todas façam isso. Não presuma que a resposta original será reproduzida nem que haverá um código de conflito específico sem confirmação do provedor.

  • Mantenha imutável o payload associado a uma chave durante as novas tentativas.
  • Defina quais campos compõem a identidade da operação.
  • Verifique o comportamento quando uma chave é repetida com um payload diferente.
  • Registre a resposta recebida sem interpretá-la como prova de entrega ao aparelho.

Planeje o tratamento de timeouts e respostas perdidas

Quando uma resposta não chega, a primeira decisão não deve ser simplesmente reenviar: é preciso determinar se a API oferece uma forma segura de repetir a solicitação com a mesma chave ou de consultar a operação. Se não houver um contrato de idempotência nem um mecanismo para conhecer o resultado, o status pode permanecer indeterminado; um novo POST pode criar outra operação.

Separe na lógica os erros cuja resposta foi recebida dos casos em que nenhuma resposta chegou. Para estes últimos, use somente as opções documentadas pela API. Não trate um timeout como prova de que o servidor não executou a solicitação.

  • Armazene a chave e os dados necessários para correlacionar a tentativa antes de enviar a solicitação.
  • Se a resposta se perder, tente novamente com a mesma chave somente se o contrato confirmar que isso é seguro.
  • Se houver uma consulta da operação ou do status, use-a antes de criar um novo envio.
  • Se não houver uma forma documentada de resolver a incerteza, evite reenviar às cegas e trate o caso como indeterminado.

Controle solicitações simultâneas e persistência

Dois processos podem tentar enviar a mesma operação ao mesmo tempo, por exemplo, se uma fila entregar novamente um trabalho enquanto outro trabalhador ainda o processa. A integração deve evitar que a concorrência local gere chaves diferentes para o mesmo evento de negócio ou perca a relação entre chave e payload.

As evidências disponíveis não definem um método universal de armazenamento atômico nem um mecanismo específico de bloqueio para uma API de SMS. Implemente o controle na camada da aplicação e confirme como a API trata solicitações simultâneas com a mesma chave. Não presuma que ela elimina duplicidades em condições de concorrência, a menos que o contrato especifique isso.

  • Persista a chave e a identidade da operação antes de despachar o envio.
  • Faça com que os trabalhadores concorrentes recuperem a mesma chave para a mesma operação.
  • Defina qual registro local prevalece se dois processos tentarem criar a operação ao mesmo tempo.
  • Teste solicitações simultâneas e verifique o comportamento documentado do endpoint.

A aceitação não confirma o status final da mensagem

Quando aceita pela API, a chave de idempotência trata da repetição de uma solicitação dentro de um contrato definido. Ela não confirma que a mensagem chegou ao aparelho nem substitui o acompanhamento de status. Mantenha separados, no modelo de dados e nos relatórios, o resultado da solicitação HTTP e as informações posteriores sobre a mensagem.

Se a solicitação foi aceita, mas o status final ainda é desconhecido, mantenha os identificadores e dados de correlação fornecidos pela API e use os mecanismos de consulta documentados. Não crie um novo envio apenas porque o status está demorando a ser atualizado. Um DLR recebido também não deve ser apresentado como verificação independente de recebimento no aparelho, a menos que essa verificação exista.

  • Registre separadamente a chave de idempotência, o resultado HTTP e os identificadores de mensagem disponíveis.
  • Consulte ou reconcilie os status usando os recursos documentados pela API.
  • Não confunda aceitação, status informado pela rota e recebimento verificado de forma independente.
  • Não prometa entrega única de ponta a ponta com base apenas na idempotência da API.
FAQ

Perguntas frequentes

Uma chave de idempotência garante que o SMS seja entregue uma única vez?

Não. Ela pode ajudar a evitar que uma API aceite mais de uma vez a mesma operação, se o serviço definir e aplicar esse contrato. Não comprova o recebimento no aparelho nem garante entrega única de ponta a ponta.

Devo repetir um envio de SMS quando ocorre um timeout?

Não às cegas. Um timeout não prova que o servidor deixou de processar a solicitação. Tente novamente com a mesma chave somente se a API documentar esse comportamento, ou consulte a operação por um mecanismo documentado.

O que acontece se eu usar a mesma chave com um payload diferente?

Depende do contrato da API. Não há uma regra universal comprovada para APIs de SMS. Mantenha o payload imutável para cada chave e confirme qual resposta o serviço retorna para uma solicitação incompatível.

Por quanto tempo uma chave deve ser mantida?

A duração depende da API. Confirme o período de retenção e alinhe a ele o período de novas tentativas do cliente; não presuma uma duração padrão.

Um DLR confirma que o usuário recebeu a mensagem no telefone?

Não deve ser tratado automaticamente como prova independente de recebimento no aparelho. Mantenha a distinção entre um status DLR informado e uma verificação independente, caso ela esteja disponível.

Fontes consultadas

  1. HTTP Semantics (RFC 9110)IETF
  2. SMPP Protocol Specification v3.4SMPP Developers Forum