Skip to content

feat(client): toute la politique de retry réglable via retry_options: - #17

Open
arsenik-dtheo[bot] wants to merge 2 commits into
epic-6/03-erreurs-connexionfrom
epic-6/04-retry-options
Open

arsenik-dtheo[bot] wants to merge 2 commits into
epic-6/03-erreurs-connexionfrom
epic-6/04-retry-options

Conversation

@arsenik-dtheo

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

Copy link
Copy Markdown
Contributor

Closes #11
Partie de l'épic #6

🔍 Ce que fait cette PR

Toute la politique de retentative devient réglable via un unique argument retry_options: (Hash) sur Client.new, hérité par Typesafe::Jev via Jev.new(retry_options:) — la signature de evaluate ne change pas. Clés acceptées : max_retries, base_delay, max_delay ; clés absentes ou valeurs nil → défauts (2 / 0,5 / 8,0) ; retry_options: nil → tous les défauts. Validation stricte à la construction : ArgumentError nommant la clé en cause sur toute clé inconnue (y compris les clés String — lecture stricte de « toute clé inconnue »), max_retries non entier ou négatif, délais négatifs ou non numériques, retry_options non-Hash. Le Hash normalisé est dupliqué, figé (retry_options frozen, client frozen) : muter le Hash passé après construction n'a plus d'effet. Les délais sont normalisés en Float. retry_options: { max_retries: 0 } redonne le comportement d'une tentative unique (HTTP et réseau).

✅ Critères couverts

  • Client.new(api_key:, retry_options: { max_retries: 0 }) n'effectue qu'une seule tentative → tests HTTP (529) et réseau (Errno::ECONNREFUSED) : have_been_requested.once, aucun sleep, erreur levée
  • base_delay et max_delay resserrent ou relâchent le backoff, observables via les délais demandés → base 1,0 → [0,5 ; 1,0] ; base 0,1 → [0,05 ; 0,1] ; plafond : base 4,0 + max_delay 0,5 → les 2 sleeps ∈ [0,25 ; 0,5]
  • Les défauts restent 2 / 0,5 / 8,0 → retry_options: nil, {}, clés toutes nil : 3 requêtes (comportement du ticket 01) et options normalisées exactement {max_retries: 2, base_delay: 0.5, max_delay: 8.0}
  • Une clé inconnue (typo) ou une valeur invalide lève une ArgumentError dès la construction, avec un message nommant la clé en cause → :max_retrie, clé String, max_retries 2.5 / -1, délais -1.0 / "x", retry_options non-Hash — sur Client et Jev
  • Le client expose les options normalisées et figées ; muter le Hash passé après construction n'a plus d'effet → tests de gel + de non-propagation
  • Typesafe::Jev.new accepte retry_options: et le transmet → options normalisées/figées + comportement reflété (tentative unique, base_delay réglé)

👀 Comment vérifier

  1. bundle exec rspec spec/typesafe/client_spec.rb -e "retry_options" — scénarios de configuration, validation et gel
  2. En vrai : Typesafe::Jev.new(api_key: k, retry_options: { max_retries: 0 }) face à un 429 lève immédiatement, là où le défaut rejouerait deux fois

🧪 Vérifications

  • Seam de test : Typesafe::Client#evaluate / Typesafe::Jev#evaluate (WebMock sur l'endpoint + stub de sommeil, délais observés via les sommes demandées) — cf. ## Décisions de test de la spec
  • typecheck propre (ruby --parser=prism -c sur lib + spec)
  • suite complète verte (268 exemples, 3 seeds)
  • diff contenu dans le périmètre du ticket (pas d'override par appel, pas d'observabilité)

⚠️ Écarts et arbitrages

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

  • validate_delay! : value.respond_to?(:>=) est toujours vrai (Object#>= existe) — la garde est morte et le rejet d'un Complex est un accident de la sémantique de >=, pas le check « non ordonnable » commenté ; à réécrire ou documenter honnêtement
  • RETRIES/BASE_DELAY/MAX_DELAY ne servent plus qu'à initialiser DEFAULT_RETRY_OPTIONS — indirection collapsable en une seule constante
  • Clés Symbol-only ici, alors que Noul/Choice normalisent String→Symbol — défendable (config de politique, pas données du domaine), choix à acter
  • L'one-shot Jev.evaluate(state:, questions:, api_key:) n'accepte pas retry_options: — le ticket ne vise que Jev.new ; à noter pour la doc (ticket 05)
  • README « Configuration » ne mentionne pas retry_options: et l'exemple Errors re-roule encore une boucle manuelle — dette doc portée par le ticket 05

📚 Références

@arsenik-dtheo
arsenik-dtheo Bot added this pull request to stack #19 September 20, 2026 23:41
retry_options: sur Client.new (et Jev.new) : défauts 2/0,5/8,0 pour clés
absentes, valeurs nil et retry_options: nil ; validation stricte (clé
inconnue ou valeur invalide -> ArgumentError nommant la clé) ; options
normalisées exposées et figées, mutation du Hash passé sans effet ;
max_retries: 0 = tentative unique ; base_delay/max_delay observables
via les délais demandés ; héritage Jev.
Client.new (et Jev.new, qui hérite) acceptent un unique argument
retry_options: (Hash) : max_retries / base_delay / max_delay, défauts
2 / 0,5 / 8,0 pour clé absente ou nil, et retry_options: nil pour tous
les défauts. Validation stricte à la construction (ArgumentError nommant
la clé sur clé inconnue ou valeur invalide : numériques non négatifs,
max_retries entier). Le Hash normalisé est dupliqué et figé, exposé sur
le client ; muter le Hash passé n'a plus d'effet. La boucle retentative
et le backoff lisent la politique configurée ; la signature de evaluate
ne change pas.
@arsenik-dtheo
arsenik-dtheo Bot force-pushed the epic-6/04-retry-options branch from c7e7464 to d28f6c2 Compare September 21, 2026 06:12
@arsenik-dtheo arsenik-dtheo Bot changed the title feat(client): toute la politique de retry réglable via retry_options: (1.4.0) feat(client): toute la politique de retry réglable via retry_options: 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.

04 : configuration via retry_options (clés, validation, héritage Jev)

0 participants