Aller au contenu

Guides

Idempotence

Une soumission réessayée ne doit jamais envoyer deux fois. L’en-tête Idempotency-Key est la garantie qu’apporte SMSend.

La clé est obligatoire, pas optionnelle

L’en-tête

Choisissez une valeur propre à la soumission, et dérivez-la de quelque chose de votre propre système plutôt que de la générer au hasard. Un identifiant de commande fait l’affaire ; un nouvel UUID à chaque tentative annule tout le mécanisme, car la reprise ressemble alors à une nouvelle requête.

Idempotency-Key: order-1042
Longueur maximale de la clé
255
Fenêtre de rejeu
24 h
Reprise d’une réservation en cours devenue obsolète après
300 s
Retry-After en cas de conflit avec une requête en vol
5 s
L’unicité est limitée à
api_key_id + key

Les trois issues

Ce qui se passe lors d’une répétition dépend de deux choses : la première requête est-elle terminée, et le corps est-il identique.

IN_PROGRESS                       →  409 REQUEST_IN_PROGRESS + Retry-After
COMPLETED, same fingerprint       →  the stored response, replayed byte for byte
COMPLETED, different fingerprint  →  409 IDEMPOTENCY_KEY_REUSED

Rejouer une requête terminée

Envoyez la même clé avec le même corps dans la fenêtre de 24 heures et vous récupérez la réponse d’origine — les octets stockés, pas une réponse recalculée — accompagnée d’un en-tête vous indiquant qu’il s’agit d’un rejeu. Rien n’est envoyé une seconde fois et rien n’est refacturé.

HTTP/1.1 202 Accepted
Idempotent-Replay: true
X-Request-Id: 01K3F7XQZ8V2N4M6P8R0T5CJWE

Réutiliser une clé pour une autre requête

La même clé avec un corps différent est un conflit, pas un rejeu. Cela attrape le bogue où une clé est dérivée de quelque chose d’insuffisamment spécifique et où deux lots réellement différents entrent en collision.

409 Conflict
{
  "error": {
    "code": "IDEMPOTENCY_KEY_REUSED",
    "message": "This Idempotency-Key has already been used for a different request. Use a new key.",
    "retryable": false,
    "detail": { "idempotency_key": "order-1042" },
    "request_id": "01K3F7XQZ8V2N4M6P8R0T5CJWE"
  }
}

Réessayer pendant que la première tentative tourne encore

Si la requête d’origine n’est pas terminée, la reprise est refusée avec une erreur réessayable et un Retry-After. Attendez et recommencez — la réservation est libérée dès que la première tentative s’achève.

409 Conflict
{
  "error": {
    "code": "REQUEST_IN_PROGRESS",
    "message": "A request with this Idempotency-Key is already in progress. Retry shortly.",
    "retryable": true,
    "detail": { "idempotency_key": "order-2000" },
    "request_id": "01K3F7XQZ8V2N4M6P8R0T5CJWE"
  }
}

Comment le corps est comparé

L’empreinte est un hachage de la méthode, du chemin et de la charge utile dont les clés d’objet sont triées récursivement. Trier les clés signifie qu’un client dont la bibliothèque JSON sérialise les champs dans un autre ordre lors de la reprise produit tout de même la même empreinte.

Une soumission refusée libère la clé

Si un lot est refusé — pour fonds insuffisants, par exemple — l’enregistrement d’idempotence est supprimé plutôt que conservé. Vous pouvez donc recharger le portefeuille et réessayer la requête identique avec la clé identique, ce qui est exactement ce que veut l’appelant et ce qu’une implémentation naïve interdirait pendant 24 heures.