11package oai
22
33import (
4- mathrand "math/rand"
5- "net/http"
6- "strings"
7- "time"
4+ mathrand "math/rand"
5+ "net/http"
6+ "strings"
7+ "time"
88)
99
1010// RetryPolicy controls HTTP retry behavior for transient failures.
@@ -13,80 +13,80 @@ import (
1313// JitterFraction specifies the +/- fractional jitter applied to each computed backoff.
1414// When Rand is non-nil, it is used to sample jitter for deterministic tests.
1515type RetryPolicy struct {
16- MaxRetries int
17- Backoff time.Duration
18- JitterFraction float64
19- Rand * mathrand.Rand
16+ MaxRetries int
17+ Backoff time.Duration
18+ JitterFraction float64
19+ Rand * mathrand.Rand
2020}
2121
2222// backoffDuration returns the duration that sleepBackoff would sleep for a given attempt.
2323func backoffDuration (base time.Duration , attempt int ) time.Duration {
24- if base <= 0 {
25- base = 200 * time .Millisecond
26- }
27- d := base << attempt
28- if d > 2 * time .Second {
29- d = 2 * time .Second
30- }
31- return d
24+ if base <= 0 {
25+ base = 200 * time .Millisecond
26+ }
27+ d := base << attempt
28+ if d > 2 * time .Second {
29+ d = 2 * time .Second
30+ }
31+ return d
3232}
3333
3434// backoffWithJitter returns an exponential backoff adjusted by +/- jitter fraction.
3535// When jitterFraction <= 0, this falls back to backoffDuration. When r is nil,
3636// a time-seeded RNG is used for production randomness.
3737func backoffWithJitter (base time.Duration , attempt int , jitterFraction float64 , r * mathrand.Rand ) time.Duration {
38- d := backoffDuration (base , attempt )
39- if jitterFraction <= 0 {
40- return d
41- }
42- if jitterFraction > 0.9 { // prevent extreme factors
43- jitterFraction = 0.9
44- }
45- if r == nil {
46- // Seed with current time for production; tests can pass a custom Rand
47- r = mathrand .New (mathrand .NewSource (time .Now ().UnixNano ()))
48- }
49- // factor in [1 - f, 1 + f]
50- minF := 1.0 - jitterFraction
51- maxF := 1.0 + jitterFraction
52- factor := minF + r .Float64 ()* (maxF - minF )
53- // Guard against rounding to zero
54- jittered := time .Duration (float64 (d ) * factor )
55- if jittered < time .Millisecond {
56- return time .Millisecond
57- }
58- return jittered
38+ d := backoffDuration (base , attempt )
39+ if jitterFraction <= 0 {
40+ return d
41+ }
42+ if jitterFraction > 0.9 { // prevent extreme factors
43+ jitterFraction = 0.9
44+ }
45+ if r == nil {
46+ // Seed with current time for production; tests can pass a custom Rand
47+ r = mathrand .New (mathrand .NewSource (time .Now ().UnixNano ()))
48+ }
49+ // factor in [1 - f, 1 + f]
50+ minF := 1.0 - jitterFraction
51+ maxF := 1.0 + jitterFraction
52+ factor := minF + r .Float64 ()* (maxF - minF )
53+ // Guard against rounding to zero
54+ jittered := time .Duration (float64 (d ) * factor )
55+ if jittered < time .Millisecond {
56+ return time .Millisecond
57+ }
58+ return jittered
5959}
6060
6161// retryAfterDuration parses the Retry-After header which may be seconds or HTTP-date.
6262// Returns (duration, true) when valid; otherwise (0, false).
6363func retryAfterDuration (h string , now time.Time ) (time.Duration , bool ) {
64- h = strings .TrimSpace (h )
65- if h == "" {
66- return 0 , false
67- }
68- // Try integer seconds first
69- if secs , err := time .ParseDuration (h + "s" ); err == nil {
70- if secs > 0 {
71- return secs , true
72- }
73- }
74- // Try HTTP-date formats per RFC 7231 (use http.TimeFormat)
75- if t , err := time .Parse (http .TimeFormat , h ); err == nil {
76- if t .After (now ) {
77- return t .Sub (now ), true
78- }
79- }
80- return 0 , false
64+ h = strings .TrimSpace (h )
65+ if h == "" {
66+ return 0 , false
67+ }
68+ // Try integer seconds first
69+ if secs , err := time .ParseDuration (h + "s" ); err == nil {
70+ if secs > 0 {
71+ return secs , true
72+ }
73+ }
74+ // Try HTTP-date formats per RFC 7231 (use http.TimeFormat)
75+ if t , err := time .Parse (http .TimeFormat , h ); err == nil {
76+ if t .After (now ) {
77+ return t .Sub (now ), true
78+ }
79+ }
80+ return 0 , false
8181}
8282
8383// sleepFor sleeps for the provided duration; extracted for testability.
8484// sleepFunc allows tests to intercept sleeps deterministically.
8585var sleepFunc = sleepFor
8686
8787func sleepFor (d time.Duration ) {
88- if d <= 0 {
89- return
90- }
91- time .Sleep (d )
88+ if d <= 0 {
89+ return
90+ }
91+ time .Sleep (d )
9292}
0 commit comments