Retour au blog Connectivité

Clés d’idempotence dans une API SMS : éviter les doublons en cas de nouvelle tentative ou de délai d’attente

Une clé d’idempotence peut aider à gérer les nouvelles tentatives d’une requête HTTP, mais seulement si l’API en définit la portée et le comportement. Découvrez les points à convenir avant de renvoyer un message et comment distinguer l’acceptation de la requête de l’état de livraison.

Schéma d’une intégration SMS montrant une clé d’idempotence, des nouvelles tentatives HTTP et la consultation de l’état du message

Quel problème l’idempotence résout-elle lors de l’envoi de SMS ?

Un client peut envoyer une requête HTTP puis perdre la connexion avant de recevoir la réponse. À ce stade, il ne sait pas nécessairement si le serveur a traité la requête. S’il renvoie à l’aveugle un envoi que l’API traite comme une nouvelle opération, il peut provoquer une seconde acceptation et, potentiellement, un doublon du message.

Une clé d’idempotence est un mécanisme qu’une API peut proposer pour reconnaître que plusieurs requêtes correspondent à une même opération. Son utilité dépend du contrat propre à cette API : la norme HTTP ne définit pas à elle seule une clé d’idempotence ni ses règles pour un endpoint d’envoi de SMS.

  • Objectif : éviter qu’une nouvelle tentative pour une même opération soit interprétée comme une nouvelle requête.
  • Limite : éviter une double acceptation ne revient pas à garantir que le message sera livré une seule fois.
  • Avant de mettre en place des nouvelles tentatives, vérifiez dans la documentation de l’API si elle accepte les clés, quelle est leur portée et quelle réponse est renvoyée lorsqu’elles sont réutilisées.
Quel problème l’idempotence résout-elle lors de l’envoi de SMS ?

Répéter une requête HTTP ne signifie pas toujours répéter le même envoi

La sémantique HTTP distingue les méthodes idempotentes des méthodes non idempotentes. Selon la RFC 9110, une opération est idempotente lorsque plusieurs requêtes identiques ont le même effet prévu sur le serveur qu’une seule. La spécification identifie des méthodes comme PUT et DELETE ; elle ne considère pas POST comme idempotente par défaut.

Il ne faut donc pas supposer qu’il est sans risque de renvoyer un POST d’envoi de SMS. Si la connexion est interrompue avant la réception de la réponse, le client peut ignorer si la requête a été exécutée. La RFC 9110 recommande de ne pas réessayer automatiquement une opération non idempotente, sauf si l’on sait que sa sémantique est idempotente ou que la requête initiale n’a pas été appliquée.

  • Un délai d’attente décrit ce que le client a observé, pas nécessairement ce qui s’est passé sur le serveur.
  • Un rejet reçu est différent d’une réponse perdue : si l’API a renvoyé une réponse, utilisez son code et son contrat pour décider de la suite.
  • Ne transformez pas toutes les erreurs HTTP, les fermetures de connexion ou les délais d’attente en renvois automatiques.
Répéter une requête HTTP ne signifie pas toujours répéter le même envoi

Générez une clé stable pour chaque opération métier

La clé doit identifier une opération logique que le système peut reconnaître lors de chacune de ses tentatives, par exemple une demande d’OTP associée à un événement interne précis. Si une nouvelle clé est générée à chaque tentative, l’API ne disposera pas d’un identifiant commun pour relier les requêtes.

La clé ne devrait pas être construite à partir de données personnelles ou de secrets superflus. Définissez sa génération et son stockage au sein de votre système, et évitez de la réutiliser pour une autre opération. Les sources disponibles ne fixent pas la méthode exacte de génération des clés, leur format ni leur entropie : ces éléments doivent être définis à partir de la documentation de l’API et des exigences de sécurité de votre intégration.

  • Attribuez une clé à l’opération métier au moment de sa création, avant la première requête HTTP.
  • Conservez la même clé pour toutes les tentatives de cette opération.
  • Créez une clé distincte pour toute nouvelle opération, même si le destinataire et le contenu sont identiques.
  • N’incluez pas d’identifiants, de jetons ni d’informations personnelles sans nécessité.

Définissez la portée et la durée avant de dépendre de la clé

Une clé n’est univoque que dans le périmètre défini par l’API. Le contrat doit préciser si elle est interprétée par compte, endpoint, opération ou selon une autre combinaison, ainsi que la durée de conservation de l’association entre la clé et la requête. Il n’existe pas de durée universelle établie pour les API SMS.

Si le client réessaie après que l’API a cessé de conserver la clé, le serveur peut traiter la requête comme une nouvelle opération. La période de rétention doit donc couvrir la durée pendant laquelle votre système peut avoir besoin de récupérer une réponse perdue, et l’application doit savoir quoi faire à l’expiration de cette période.

  • Confirmez le périmètre d’unicité de la clé et ne supposez pas qu’elle est globale.
  • Documentez la période de rétention et le comportement à son expiration.
  • Alignez la période de nouvelles tentatives du client sur la rétention prévue par le contrat.
  • Si l’API ne documente pas ces points, demandez des précisions avant d’automatiser les renvois.

Convenez du comportement en cas de réutilisation de la clé avec un autre payload

La réutilisation d’une clé avec des données différentes est un cas critique. Le contrat devrait préciser comment l’API compare les requêtes et ce qui se passe si une même clé est reçue avec un payload incompatible. Une pratique prudente consiste à ne pas réutiliser la clé pour modifier le destinataire, le contenu ou tout autre champ qui change l’opération ; la réponse concrète à ce conflit doit être vérifiée dans la documentation du service.

Il est également utile de savoir quel résultat reçoit le client lorsqu’il répète exactement la même requête. Certaines API peuvent renvoyer un résultat associé à la première opération, mais rien ne permet d’affirmer que toutes le font. Ne présumez ni que la réponse initiale sera reproduite ni qu’un code de conflit précis sera renvoyé sans confirmation du fournisseur.

  • Gardez le payload associé à une clé inchangé lors des nouvelles tentatives.
  • Définissez les champs qui constituent l’identité de l’opération.
  • Vérifiez le comportement lorsque la même clé est réutilisée avec un payload différent.
  • Consignez la réponse reçue sans la considérer comme une preuve de livraison sur le terminal.

Concevez le traitement des délais d’attente et des réponses perdues

Lorsqu’aucune réponse n’arrive, la première décision n’est pas simplement de renvoyer la requête : il faut déterminer si l’API permet de la réessayer sans risque avec la même clé ou de consulter l’opération. En l’absence de contrat d’idempotence ou de mécanisme permettant d’en connaître le résultat, l’état peut rester indéterminé ; un nouveau POST pourrait créer une autre opération.

Dans votre logique, distinguez les erreurs pour lesquelles une réponse a été reçue des cas où aucune réponse n’est parvenue. Pour ces derniers, appliquez uniquement les options documentées par l’API. Ne considérez pas un délai d’attente comme la preuve que le serveur n’a pas exécuté la requête.

  • Enregistrez la clé et les données nécessaires pour établir la corrélation avant d’envoyer la requête.
  • En cas de réponse perdue, ne réessayez avec la même clé que si le contrat confirme que cette démarche est sûre.
  • Si un mécanisme documenté de consultation de l’opération ou de son état existe, utilisez-le avant de créer un nouvel envoi.
  • S’il n’existe aucun moyen documenté de lever l’incertitude, évitez les renvois à l’aveugle et traitez le cas comme indéterminé.

Maîtrisez les requêtes simultanées et la persistance

Deux processus peuvent tenter d’envoyer simultanément la même opération, par exemple si une file d’attente remet un travail à disposition alors qu’un autre travailleur le traite encore. L’intégration doit empêcher que la concurrence locale génère des clés différentes pour le même événement métier ou rompe le lien entre la clé et le payload.

Les éléments disponibles ne définissent pas de méthode universelle de stockage atomique ni de mécanisme précis de verrouillage pour une API SMS. Concevez le contrôle dans la couche applicative et vérifiez comment l’API traite les requêtes simultanées portant la même clé. Ne supposez pas qu’elle déduplique les requêtes concurrentes, sauf si le contrat le précise.

  • Enregistrez la clé et l’identité de l’opération avant de lancer l’envoi.
  • Faites en sorte que les travailleurs concurrents récupèrent la même clé pour la même opération.
  • Définissez quel enregistrement local prévaut si deux processus tentent de créer l’opération au même moment.
  • Testez les requêtes simultanées et vérifiez le comportement documenté de l’endpoint.

L’acceptation ne confirme pas l’état final du message

Lorsqu’une API les prend en charge, les clés d’idempotence encadrent la répétition d’une requête selon un contrat défini. Elles ne confirment pas que le message est arrivé sur le terminal et ne remplacent pas le suivi de son état. Dans votre modèle de données et vos rapports, distinguez le résultat de la requête HTTP des informations ultérieures sur le message.

Si la requête a été acceptée mais que son état final n’est pas encore connu, conservez les identifiants et les données de corrélation fournis par l’API et utilisez les mécanismes de consultation documentés. Ne créez pas un nouvel envoi uniquement parce que l’état tarde à être mis à jour. Un DLR reçu ne doit pas non plus être présenté comme une vérification indépendante de la réception sur le terminal, sauf si une telle vérification existe.

  • Consignez séparément la clé d’idempotence, le résultat HTTP et les identifiants de message disponibles.
  • Consultez ou rapprochez les états au moyen des fonctionnalités documentées par l’API.
  • Ne confondez pas l’acceptation, l’état communiqué par la route et la réception vérifiée de manière indépendante.
  • Ne promettez pas une livraison unique de bout en bout sur la seule base de l’idempotence de l’API.
FAQ

Questions fréquentes

Une clé d’idempotence garantit-elle que le SMS sera livré une seule fois ?

Non. Elle peut aider à éviter qu’une API accepte plusieurs fois la même opération, si le service définit et applique un tel contrat. Elle ne prouve pas la réception sur le terminal et ne garantit pas une livraison unique de bout en bout.

Dois-je réessayer un envoi de SMS en cas de délai d’attente ?

Pas à l’aveugle. Un délai d’attente ne prouve pas que le serveur n’a pas traité la requête. Réessayez avec la même clé uniquement si l’API documente ce comportement, ou consultez l’opération au moyen d’un mécanisme documenté.

Que se passe-t-il si j’utilise la même clé avec un payload différent ?

Cela dépend du contrat de l’API. Il n’existe pas de règle universelle établie pour les API SMS. Gardez le payload inchangé pour chaque clé et vérifiez quelle réponse le service renvoie à une requête incompatible.

Combien de temps faut-il conserver une clé ?

La durée dépend de l’API. Confirmez sa période de rétention et alignez sur celle-ci la période de nouvelles tentatives de votre client ; ne supposez pas qu’il existe une durée standard.

Un DLR confirme-t-il que l’utilisateur a reçu le message sur son téléphone ?

Il ne faut pas automatiquement le considérer comme une preuve indépendante de réception sur le terminal. Distinguez l’état communiqué par un DLR d’une vérification indépendante, si celle-ci est disponible.

Sources consultées

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