feat(client): honore Retry-After / Retry-After-Ms sur 429 - #15
Open
arsenik-dtheo[bot] wants to merge 3 commits into
Open
arsenik-dtheo[bot] wants to merge 3 commits into
arsenik-dtheo[bot] wants to merge 3 commits into
Conversation
arsenik-dtheo
Bot
force-pushed
the
epic-6/02-retry-after
branch
from
September 21, 2026 06:12
35c9da1 to
37c839a
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #9
Partie de l'épic #6
🔍 Ce que fait cette PR
Quand un 429 porte un en-tête
Retry-After(secondes) ouRetry-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 parRateLimitError#retry_after(déjà existant) et reste réservé au 429 — les 529/5xx conservent le backoff.✅ Critères couverts
Retry-After: 2provoque 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)Retry-After-Ms: 250provoque une attente de 0,25 seconde →expect(sleeps).to eq([0.25])Retry-Afternon 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👀 Comment vérifier
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êtesRetry-After: 30ne reprend pas avant 30 s, au lieu de rejouer trop tôt avec son backoff maison🧪 Vérifications
Typesafe::Client#evaluate(WebMock sur l'endpoint + stub de sommeil) — cf.## Décisions de testde la specruby -csur lib + spec ; aucune toolchain de types Ruby dans ce dépôt)retry_options:— ticket 04)Signalements
[NIT]de la revue (cycle 1/2, verdict APPROVED), non bloquants, non corrigés ici :Retry-After: 1e999→Infinity) ferait encore fuir uneRangeErrorhors deevaluate— même classe de bug que le bloquant corrigé, à une vérificationfinite?près ; aucun serveur n'émet cela et le stub de sommeil rend la suite structurellement aveugle aux mauvais arguments de sleep37c839achangelib/sans bump de version — la version de l'épic est bumpée une seule fois, par le PR final (ticket 05)evaluateet dedelay_before_retry) — risque de dérive, à ressouder au ticket 05error.is_a?(RateLimitError)est un type-sniffing ; hisserretry_aftersurAPIErrorsupprimerait la branche — jugement, non appliqué ici📚 Références
docs/plans/retry-client/spec.mdepic-6/01-retentatives-defaut←epic-6/02-retry-after