Plus facile à lire avec un fond crème, une teinte, plus de contraste ou un texte plus grand ? Choisissez vos couleurs et votre texte, une fois pour toutes les pages.

Leçon gratuite

Réessayer après une erreur d’API

Après cette leçon: Je peux distinguer un échec à réessayer d’un échec à corriger.

Leçon de 60 min5 commandesLab agent de code IA : utiliser opencode pour expliquer et corriger du code, et vérifier son travail

Certains échecs passent si on attend

Une erreur d’API est une réponse dont le code d’état dit que l’appel n’a pas marché. Certaines erreurs passent si on attend un peu et qu’on réessaie. D’autres ne passent jamais, quel que soit le nombre d’essais.

Un bon programme sait distinguer les deux. Il réessaie le premier cas avec des attentes croissantes, et il s’arrête et signale le second.

À la fin de cette leçon

Remarque

Je peux distinguer un échec à réessayer d’un échec à corriger.

Mots clés

MotCe que ça veut direExemple
Code d’étatun nombre dans une réponse qui dit comment l’appel s’est passé429
Limite de débitun plafond du nombre d’appels permis par minute
Reculattendre plus longtemps après chaque essai raté
Aléaun changement au hasard d’une attente, pour que les clients ne réessaient pas ensemble
Délai d’attentele temps maximal pendant lequel on attend une réponse

Les cellules que les étudiants remplissent restent vides dans cet aperçu.

Le code d’état dit quoi faire ensuite

Un statut en 200 veut dire que l’appel a marché. Un statut en 400 veut le plus souvent dire que votre appel est mal fait, donc le même appel échouera encore.

D’autres statuts signalent un problème bref et passager : un délai dépassé, un serveur occupé ou une limite de débit. Pour ceux-là, attendre puis réessayer est la bonne réaction.

Exemple travaillé : réessayer ou corriger

StatutCe que cela veut direQue faire
400La requête est fausseCorriger la requête
401Pas de clé valideCorriger la clé
403Pas autorisé, ou plus de créditCorriger la cause
408, 504Un délai dépasséRéessayer
429Trop de requêtesAttendre, puis réessayer
500, 502, 503Le serveur a un problèmeRéessayer quelques fois

Les cellules que les étudiants remplissent restent vides dans cet aperçu.

Trier des statuts et lire un 429 enregistré

Commande
docker exec -w /home/node/project agent node -e '/* Quels échecs méritent un nouvel essai ? */ const genre = (statut) => { if (statut >= 200 && statut < 300) return "ok"; return [408, 429, 500, 502, 503, 504].includes(statut) ? "réessayer" : "corriger"; }; const notes = { 200: "cela a marché", 400: "la requête est fausse", 401: "pas de clé valide", 403: "pas autorisé", 408: "délai dépassé", 429: "trop de requêtes", 500: "le serveur est en panne", 503: "le serveur n’est pas prêt" }; for (const statut of Object.keys(notes)) { console.log(statut + " " + genre(Number(statut)).padEnd(9) + " " + notes[statut]); } /* Un 429 enregistré, écrit dans ce script comme donnée. Aucun appel n’est fait. */ const enregistre = { statut: 429, entetes: { "retry-after": "2" }, corps: { error: { message: "Trop de requêtes, ralentissez." } } }; console.log("429 enregistré : " + enregistre.corps.error.message + " Le serveur demande " + enregistre.entetes["retry-after"] + " secondes.");'

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Le recul attend plus longtemps à chaque fois

Si vous réessayez aussitôt, vous ajoutez à la charge qui a causé l’échec. Le recul attend un peu, puis deux fois plus, puis deux fois plus encore, jusqu’à un plafond.

Ajoutez de l’aléa : changez chaque attente d’une valeur au hasard, entre la moitié et le tout. Ainsi cent clients qui ont échoué ensemble ne réessaient pas au même instant. Si la réponse a un en-tête Retry-After, servez-vous-en.

Afficher un calendrier de recul

Commande
docker exec -w /home/node/project agent node -e '/* Attendre plus longtemps après chaque échec, jusqu’à un plafond, avec de l’aléa. */ const base = 1; const plafond = 8; const delais = []; for (let tentative = 0; tentative < 6; tentative++) delais.push(Math.min(plafond, base * 2 ** tentative)); console.log("Délais en secondes : " + delais.join(", ")); const avecAleas = delais.map((un) => un / 2 + Math.random() * un / 2); console.log("Avec aléa, une exécution possible : " + avecAleas.map((un) => un.toFixed(2)).join(", ")); console.log("Chaque délai avec aléa est compris entre la moitié du délai et le délai entier.");'

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Une erreur fréquente

Attention

Beaucoup pensent qu’il faut réessayer toute erreur. Ce n’est pas le cas. Un 400 ou un 401 échouera de la même façon à chaque fois. Une boucle qui le réessaie ne fait que perdre du temps et du crédit. Réessayez seulement les échecs qui peuvent passer, et quelques fois seulement.

Un délai d’attente évite d’attendre sans fin

Certains appels ne répondent jamais. Fixez un délai d’attente, le temps maximal que vous attendez, et traitez le dépassement comme un échec qui mérite un nouvel essai.

L’aide ci-dessous réunit les pièces. Elle a un délai d’attente, quelques essais et un recul avec aléa. Elle s’arrête aussitôt pour un échec à corriger, et elle affiche un exemple enregistré quand rien ne marche.

Écrire reessai.js, partie 1

Commande
docker exec -w /home/node/project agent node -e 'require("fs").writeFileSync("reessai.js", ["// reessai.js, partie 1 : quels statuts réessayer, et combien de temps attendre.", "const labo = require(\"./labo.js\");", "const genre = (statut) => {", "  if (statut >= 200 && statut < 300) return \"ok\";", "  return [408, 429, 500, 502, 503, 504].includes(statut) ? \"réessayer\" : \"corriger\";", "};", "const pause = (ms) => new Promise((fini) => setTimeout(fini, ms));", "", "// Recul, en-tête Retry-After s’il existe, plafond, et aléa.", "function attenteAvant(tentative, reponse) {", "  let attente = 150 * 2 ** tentative;", "  if (reponse) attente = Math.max(attente, Number(reponse.headers.get(\"retry-after\")) * 1000 || 0);", "  attente = Math.min(attente, 3000);", "  return attente / 2 + Math.random() * attente / 2;", "}"].join("\n") + "\n")'

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Ajouter la boucle de nouveaux essais

Commande
docker exec -w /home/node/project agent node -e 'require("fs").appendFileSync("reessai.js", ["", "// Partie 2 : réessayer, sauf pour un échec à corriger.", "async function appelerAvecReessai(corps, essais) {", "  for (let i = 1; i <= essais; i++) {", "    let reponse = null;", "    try {", "      reponse = await labo.envoyer(corps, 15000);", "      if (reponse.ok) return { ok: true, donnees: await reponse.json() };", "      console.log(\"essai \" + i + \" : HTTP \" + reponse.status);", "      if (genre(reponse.status) === \"corriger\") return { ok: false, raison: \"à corriger, pas à réessayer\" };", "    } catch (erreur) {", "      console.log(\"essai \" + i + \" : pas de réponse (\" + erreur.name + \")\");", "    }", "    if (i < essais) await pause(attenteAvant(i, reponse));", "  }", "  return { ok: false, raison: \"abandon après \" + essais + \" essais\" };", "}", "", "module.exports = { appelerAvecReessai };"].join("\n") + "\n")'

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Appeler le modèle avec des nouveaux essais

Commande
docker exec -w /home/node/project agent node -e 'const { appelerAvecReessai } = require("./reessai.js"); (async () => { const corps = { max_tokens: 20, messages: [{ role: "user", content: "Dites bonjour en un mot." }] }; const resultat = await appelerAvecReessai(corps, 3); if (resultat.ok) console.log("Réponse du modèle : " + resultat.donnees.choices[0].message.content); else console.log("Exemple enregistré : Bonjour. (" + resultat.raison + ")"); })();'

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Pour aller plus loin : changer les essais

Dans reessai.js, remplacez la première attente de 150 par 50. Dans le dernier Run, passez le nombre d’essais de 3 à 5. Lancez-le et lisez ce qu’il affiche.

Dites ce que vous choisiriez pour un bouton devant lequel une personne attend, et ce que vous choisiriez pour une tâche qui tourne la nuit.

À propos de ce labo et de sa source: Lab agent de code IA : utiliser opencode pour expliquer et corriger du code, et vérifier son travail

Vous enseignez à une classe ? Proposez ce module à vos étudiants avec un guide de l'enseignant, des devoirs corrigés et un laboratoire pour chaque étudiant.