Idempotency — E-commerce Production Guide¶
Contexte¶
L'idempotence garantit qu'une même opération peut être exécutée plusieurs fois sans effet de bord supplémentaire. Critique pour l'e-commerce où les retries réseau peuvent créer des doublons de paiements ou de commandes.
Implementation¶
Middleware¶
IdempotencyMiddleware intercepte les requêtes POST avec un header Idempotency-Key et cache la réponse pendant 24h
par défaut.
Workflow:
- Client envoie
POST /ordersavecIdempotency-Key: <uuid> - Middleware vérifie le cache
- Hit → rejoue la réponse cachée avec
X-Idempotency-Replay: true - Miss → exécute la requête, cache la réponse si 2xx
- Hit → rejoue la réponse cachée avec
- Requêtes suivantes avec la même clé retournent la réponse cachée
Configuration (_sample/config/http.yaml):
| YAML | |
|---|---|
Le cache utilisé par le middleware est le cache technique Arclith. cache/memory
est adapté aux tests et au mono-processus; utiliser cache/redis dès que plusieurs
workers, replicas Kubernetes ou processus API/MCP doivent partager les clés
idempotentes.
Usage Client¶
cURL:
JavaScript (Fetch API):
Python (httpx):
Cas d'usage E-commerce¶
1. Paiements¶
Problème: Double charge si retry réseau pendant la transaction Stripe/PayPal.
Solution:
| Python | |
|---|---|
Notre middleware implémente la même convention pour nos propres endpoints.
2. Création de commande¶
Problème: Double commande si timeout pendant la création.
Solution:
3. Webhooks¶
Problème: Stripe/PayPal peuvent renvoyer le même webhook plusieurs fois.
Solution:
Limitations¶
-
TTL fixe: Après 24h, la clé expire → retry peut créer un doublon
- Mitigation: Utiliser
required: true+ check DB côté service
- Mitigation: Utiliser
-
Cache partagé: En multi-tenant, isoler par tenant
- Solution: Cache key =
idempotency:{tenant_id}:{path}:{key}
- Solution: Cache key =
-
Réponse différente: Si le handler retourne une réponse différente avec la même clé
- Détection: Impossible sans hashing de la réponse (non implémenté)
- Best practice: Clé doit être liée à une intention métier stable
Comparaison avec l'industrie¶
| Provider | Header Name | TTL | Required |
|---|---|---|---|
| Stripe | Idempotency-Key |
24h | Recommended |
| PayPal | PayPal-Request-Id |
45 days | Optional |
| AWS | x-amz-sdk-invocation-id |
Variable | Optional |
| Twilio | Idempotency-Key |
24h | Optional |
| Arclith | Idempotency-Key |
24h (configurable) | Optional (configurable) |
Monitoring¶
Métriques recommandées:
idempotency_cache_hit_rate— % de requêtes rejouées depuis le cacheidempotency_key_missing_rate— % de POST sans cléidempotency_cache_size— Nombre de clés actives
Logs:
| Text Only | |
|---|---|
Migration en production¶
Phase 1: Déployer avec required: false (optionnel)
Phase 2: Monitorer adoption client (logs idempotency_key_missing_rate)
Phase 3: Passer à required: true pour les endpoints critiques
Phase 4: Documenter dans l'API reference (OpenAPI)
| YAML | |
|---|---|
Références¶
- **RFC Draft: ** draft-ietf-httpapi-idempotency-key-header
- Stripe: Idempotent Requests
- PayPal: Idempotency
- **AWS: ** Making idempotent API requests