Borner les réessais HTTP avec un délai et gérer les résultats inconnus
Séparez le délai d'une requête du budget total de réessai, interprétez Retry-After et évitez de dupliquer les écritures lorsque le résultat du serveur est inconnu.
Dans ce guide
La réponse courte
Donnez à l'ensemble de l'opération un budget unique et vérifiez le temps restant avant chaque tentative et chaque attente. Ne réessayez que les méthodes, erreurs et codes de statut autorisés par le contrat de l'API. Respectez une valeur Retry-After valide sans prolonger le délai. Un timeout ne prouve pas qu'une écriture a échoué : reconciliez un résultat de POST inconnu ou utilisez le mécanisme de déduplication documenté par le serveur.
Budgétiser l'ensemble de l'opération
Un délai par tentative limite une seule requête. Un délai total limite l'opération sur l'ensemble des tentatives et des périodes d'attente. Démarrer un délai frais de dix secondes pour chaque réessai peut transformer une opération destinée à durer dix secondes en une opération beaucoup plus longue.
Choisissez une horloge et un mécanisme d'annulation adaptés à l'environnement d'exécution, et vérifiez à nouveau le délai après la reprise de l'exécution. Une vérification de l'horloge entre les tentatives n'annule pas elle-même une requête en cours. Une implémentation complète nécessite à la fois des vérifications de planification et l'annulation des travaux qui dépassent l'opération.
Comprendre le mécanisme de délai
Dans les navigateurs, AbortSignal.timeout mesure le temps actif. Ce temps peut se mettre en pause pendant qu'un worker est suspendu ou qu'un document est dans le cache back-forward. Ne le décrivez pas comme un délai de temps réel universel.
Si fetch reçoit un signal d'abandon, il peut être interrompu lorsque ce signal s'abandonne. Combiner des signaux ne supprime pas la nécessité de définir une politique d'annulation globale. Ce guide explique la politique plutôt que de fournir une bibliothèque de réessai complète ; les minuteries, le traitement des corps de réponse et le nettoyage doivent être gérés par l'implémentation réelle.
Décider quelles requêtes peuvent être réessayées
L'idempotence HTTP décrit l'effet intended de la répétition d'une requête identique. Les méthodes sûres comme GET sont idempotentes, et PUT et DELETE le sont aussi par leurs sémantiques définies. Cela ne signifie pas que chaque répétition renvoie le même code ou que l'implémentation serveur est correcte.
Ne réessayez pas automatiquement toute réponse infructueuse. Une erreur de validation permanente ne doit pas entrer dans la même politique qu'une défaillance de service transitoire. POST et PATCH ne sont pas garantis idempotentes, donc un résultat inconnu nécessite le contrat spécifique de reconcilation ou de déduplication de l'API.
Interpréter Retry-After avant la planification
Retry-After peut contenir un nombre non négatif de secondes ou une date HTTP. Un délai en secondes est mesuré après réception de la réponse. Les dates HTTP nécessitent une comparaison avec l'heure actuelle et peuvent être affectées par des différences d'horloge. Une valeur manquante ou malformée n'autorise pas un réessai illimité ou immédiat.
L'extrait suivant est un fragment illustratif d'en-tête de réponse, pas une réponse observée ni une configuration serveur complète. Il demande au client d'attendre 120 secondes. Si ce délai ne peut pas s'inscrire dans le budget restant de l'opération, arrêtez plutôt que de raccourcir le délai demandé et de réessayer plus tôt.
HTTP/1.1 503 Service Unavailable
Retry-After: 120Tracer une chronologie cohérente
Supposons une opération hypothétique qui démarre à l'instant zéro avec un délai de dix secondes. La tentative 1 échoue, et le back-off choisi permet à la tentative 2 de démarrer à trois secondes. Pour cet exemple, supposons que sa réponse 503 est reçue à ce même instant avec Retry-After: 120.
Sept secondes restent, mais l'attente demandée est de 120 secondes. La décision attendue est d'arrêter avec une raison telle que retry_after_exceeds_deadline. Il n'y a pas de troisième tentative. Ce sont des valeurs construites pour expliquer la décision, pas des mesures issues d'un test réseau.
Si la même réponse hypothétique demandait trois secondes, attendre jusqu'à l'instant six laisserait quatre secondes. Une autre tentative n'est possible que si la politique le permet et si son travail est borné par ces quatre secondes restantes ; la chronologie ne promet pas que la requête réussira.
Borner le back-off et le nombre de tentatives
Quand l'API autorise les réessais et ne fournit pas de valeur Retry-After utilisable, une politique de back-off limité peut étaler les tentatives dans le temps. L'ajout d'aléa (jitter) varie les périodes d'attente pour éviter que des clients synchronisés n'arrivent ensemble de manière répétée. Définissez la limite, l'aléa et le nombre maximum de tentatives comme politique applicative plutôt que de prétendre que la norme HTTP fournit un algorithme universel.
Avant de dormir, vérifiez si l'attente choisie laisse assez de temps pour une tentative suivante utile. Arrêtez quand ce n'est pas le cas. Une valeur Retry-After importante est une raison d'abandonner une opération courte, pas une raison de limiter l'attente demandée par le serveur et de réessayer avant son expiration.
Reconcilier un résultat d'écriture inconnu
Si une connexion disparaît après qu'une requête d'écriture a pu être envoyée, le serveur a peut-être validé même si le client n'a reçu aucune réponse. Répéter un POST à effet peut créer une deuxième commande ou facturation. Gardez la distinction entre succès confirmé, échec confirmé et résultat inconnu.
Un point de terminaison de statut documenté ou un contrat de clé d'idempotence peut aider à reconciler le résultat. Réutilisez une clé seulement selon ce contrat, y compris son chargement utile et ses règles de rétention. Envoyer un en-tête arbitraire ne rend pas le serveur déduplicateur, et une consultation de statut n'est pas elle-même une permission d'émettre une deuxième écriture.
Enregistrer la raison de chaque décision
Des diagnostics utiles incluent la méthode, le numéro de tentative, le budget restant, le code de statut de la réponse, l'attente analysée et la raison d'arrêt. Gardez les identifiants, les en-têtes d'autorisation et les corps de requête sensibles hors de ces enregistrements.
Distinguez un arrêt de politique d'une défaillance de transport pour que les opérateurs sachent si le budget a été épuisé, si le serveur a demandé une attente plus longue, ou si une écriture nécessite une reconcilation. Ensuite, examinez des cas de défaillance représentatifs par rapport à la documentation de l'API. La chronologie illustrative établit l'arithmétique, pas la fiabilité ou les performances d'un client déployé.
Points à vérifier
- Un budget d'opération unique couvre toutes les tentatives et les attentes.
- Une valeur Retry-After valide n'est pas raccourcie pour forcer un réessai plus tôt.
- Les méthodes et codes de statut réessayables proviennent du contrat de l'API.
- Les résultats d'écriture inconnus sont reconcilés plutôt que répétés aveuglément.
- L'annulation à l'exécution et la gestion des données sensibles sont explicites.
Champ d’application
L'exemple de chronologie est hypothétique. Ce guide n'implémente pas un client de réessai complet ni ne prétend que l'annulation du temps actif du navigateur applique chaque délai de temps réel. Le comportement correct dépend de l'environnement d'exécution, de la sémantique du serveur et du contrat de l'application.