1515 "x-instant-test-rate-limit-reset" ,
1616 }
1717 resetHeaderPattern = regexp .MustCompile (`^\s*[0-9]+\s*$` )
18+ timeNow = time .Now
1819)
1920
2021// Custom backoff function
@@ -23,41 +24,71 @@ func customBackoff(min, max time.Duration, attemptNum int, resp *http.Response)
2324 return 0
2425 }
2526
27+ if resp .StatusCode == http .StatusTooManyRequests || resp .StatusCode == http .StatusServiceUnavailable {
28+ if sleep , ok := parseRetryAfterHeader (resp .Header ["Retry-After" ]); ok {
29+ return sleep
30+ }
31+ }
32+
2633 for _ , header := range rateLimitResetHeaders {
2734 if resetTimeStr := resp .Header .Get (header ); resetTimeStr != "" {
28- if waitDuration := parseResetHeader (& resetTimeStr ); waitDuration != nil {
29- return * waitDuration
35+ if sleep , ok := parseResetHeader (& resetTimeStr ); ok {
36+ return sleep
3037 }
3138
3239 // Default backoff if no valid reset time is found
3340 return retryablehttp .DefaultBackoff (min , max , attemptNum , resp )
3441 }
3542 }
3643
37- // Default case for no rateLimitResetHeaders
44+ // Default case for no Retry-After and rateLimitResetHeaders
3845 return retryablehttp .DefaultBackoff (min , max , attemptNum , resp )
3946}
4047
48+ func parseRetryAfterHeader (headers []string ) (time.Duration , bool ) {
49+ if len (headers ) == 0 || headers [0 ] == "" {
50+ return 0 , false
51+ }
52+ header := headers [0 ]
53+ // Retry-After: 120
54+ if sleep , err := strconv .ParseInt (header , 10 , 64 ); err == nil {
55+ if sleep < 0 { // a negative sleep doesn't make sense
56+ return 0 , false
57+ }
58+ return time .Second * time .Duration (sleep ), true
59+ }
60+
61+ // Retry-After: Fri, 31 Dec 1999 23:59:59 GMT
62+ retryTime , err := time .Parse (time .RFC1123 , header )
63+ if err != nil {
64+ return 0 , false
65+ }
66+ if until := retryTime .Sub (timeNow ()); until > 0 {
67+ return until , true
68+ }
69+ // date is in the past
70+ return 0 , true
71+ }
72+
4173// Function to parse the reset header
42- func parseResetHeader (value * string ) * time.Duration {
74+ func parseResetHeader (value * string ) ( time.Duration , bool ) {
4375 if value == nil || ! resetHeaderPattern .MatchString (* value ) {
44- return nil
76+ return 0 , false
4577 }
4678
4779 // Parse the header value to a Unix timestamp
4880 resetTimeUnix , err := strconv .ParseInt (* value , 10 , 64 )
4981 if err != nil {
50- return nil
82+ return 0 , false
5183 }
5284
5385 // Calculate the duration until the reset time
5486 resetTime := time .Unix (resetTimeUnix , 0 )
5587 waitDuration := time .Until (resetTime )
5688
57- // Return nil if the reset time has already passed
89+ // Return 0 if the reset time has already passed
5890 if waitDuration < 0 {
59- zeroDuration := time .Duration (0 )
60- return & zeroDuration
91+ return 0 , true
6192 }
62- return & waitDuration
93+ return waitDuration , true
6394}
0 commit comments