Skip to content

feat(client): honore Retry-After / Retry-After-Ms sur 429 - #15

Open
arsenik-dtheo[bot] wants to merge 3 commits into
epic-6/01-retentatives-defautfrom
epic-6/02-retry-after
Open

arsenik-dtheo[bot] wants to merge 3 commits into
epic-6/01-retentatives-defautfrom
epic-6/02-retry-after

Conversation

@arsenik-dtheo

@arsenik-dtheo arsenik-dtheo Bot commented Sep 20, 2026

Copy link
Copy Markdown
Contributor

Closes #9
Partie de l'épic #6

🔍 Ce que fait cette PR

Quand un 429 porte un en-tête Retry-After (secondes) ou Retry-After-Ms (millisecondes), la retentative attend exactement le délai demandé par le serveur au lieu du backoff exponentiel : le serveur impose le rythme. Un 429 sans en-tête, avec un en-tête non numérique ou non positif (≤ 0) retombe sur la politique par défaut du ticket 01 (0,5 s → 8 s, doublement, jitter). Le comportement passe par RateLimitError#retry_after (déjà existant) et reste réservé au 429 — les 529/5xx conservent le backoff.

✅ Critères couverts

  • Un 429 avec Retry-After: 2 provoque une attente de 2 secondes avant la retentative → spec/typesafe/client_spec.rb : expect(sleeps).to eq([2.0]) (délai demandé au stub de sommeil)
  • Un 429 avec Retry-After-Ms: 250 provoque une attente de 0,25 seconde → expect(sleeps).to eq([0.25])
  • Un en-tête Retry-After non numérique est ignoré sans planter : retombée sur le backoff par défaut → "soon"be_between(0.25, 0.5) ; idem pour un en-tête numérique non positif (-1, 0) — tests ajoutés au cycle de correction
  • Un 429 sans en-tête conserve le backoff exponentiel du ticket 01 → test dédié sur la plage de backoff

👀 Comment vérifier

  1. bundle exec rspec spec/typesafe/client_spec.rb -e "retries" — 18 exemples verts, dont les délais demandés au stub de sommeil égalent ceux des en-têtes
  2. En vrai : un client qui reçoit un 429 avec Retry-After: 30 ne reprend pas avant 30 s, au lieu de rejouer trop tôt avec son backoff maison

🧪 Vérifications

  • Seam de test : Typesafe::Client#evaluate (WebMock sur l'endpoint + stub de sommeil) — cf. ## Décisions de test de la spec
  • typecheck propre (ruby -c sur lib + spec ; aucune toolchain de types Ruby dans ce dépôt)
  • suite complète verte (225 exemples)
  • diff contenu dans le périmètre du ticket (pas de retry réseau — ticket 03 ; pas de retry_options: — ticket 04)

⚠️ Écarts et arbitrages

Signalements [NIT] de la revue (cycle 1/2, verdict APPROVED), non bloquants, non corrigés ici :

  • Un en-tête non fin mais positif (Retry-After: 1e999Infinity) ferait encore fuir une RangeError hors de evaluate — même classe de bug que le bloquant corrigé, à une vérification finite? près ; aucun serveur n'émet cela et le stub de sommeil rend la suite structurellement aveugle aux mauvais arguments de sleep
  • L'entrée CHANGELOG (Unreleased) ne mentionne que l'en-tête « non numérique » ; après correction, les numériques non positifs retombent aussi sur le backoff — le ticket 05 (documentation) harmonisera
  • Le commit de correction 37c839a change lib/ sans bump de version — la version de l'épic est bumpée une seule fois, par le PR final (ticket 05)
  • La formule de backoff est dupliquée en prose à trois endroits (docs de constantes, d'evaluate et de delay_before_retry) — risque de dérive, à ressouder au ticket 05
  • Le test error.is_a?(RateLimitError) est un type-sniffing ; hisser retry_after sur APIError supprimerait la branche — jugement, non appliqué ici

📚 Références

@arsenik-dtheo
arsenik-dtheo Bot added this pull request to stack #19 September 20, 2026 23:41
@arsenik-dtheo
arsenik-dtheo Bot force-pushed the epic-6/02-retry-after branch from 35c9da1 to 37c839a Compare September 21, 2026 06:12
@arsenik-dtheo arsenik-dtheo Bot changed the title feat(client): honore Retry-After / Retry-After-Ms sur 429 (1.2.0) feat(client): honore Retry-After / Retry-After-Ms sur 429 Sep 21, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

02 : le serveur impose le rythme (Retry-After honoré)

0 participants