@@ -120,72 +120,64 @@ function github_retry_decision(method::String, resp::Union{HTTP.Response, Nothin
120120 end
121121
122122 # At this point we have a response with status >= 400
123+ # First let us see if we want to retry it.
123124
124- # Handle GitHub rate limiting (403, 429) with special logic
125- if status in (403 , 429 )
126- # Get all rate limit headers
127- limit = HTTP. header (resp, " x-ratelimit-limit" , " " )
128- remaining = HTTP. header (resp, " x-ratelimit-remaining" , " " )
129- used = HTTP. header (resp, " x-ratelimit-used" , " " )
130- reset_time = HTTP. header (resp, " x-ratelimit-reset" , " " )
131- resource = HTTP. header (resp, " x-ratelimit-resource" , " " )
132- retry_after = HTTP. header (resp, " retry-after" , " " )
133-
134- # Check response body for secondary rate limit indicators
135- # Note: `String` takes ownership / removes the body, so we make a copy
136- body = String (copy (resp. body))
137- is_secondary_rate_limit = occursin (" secondary rate limit" , lowercase (body)) || ! isempty (retry_after)
138- if is_secondary_rate_limit
139- # Secondary rate limit handling
140- # If retry-after header is present, respect it
141- delay_seconds = safe_tryparse (Float64, retry_after)
142- if delay_seconds != = nothing
143- delay_seconds = parse (Float64, retry_after)
144- verbose && @info " GitHub API secondary rate limit hit, retrying in $(round (delay_seconds, digits= 1 )) s" method= method status= status limit= limit remaining= remaining used= used reset= reset_time resource= resource retry_after= retry_after
145- return (true , delay_seconds)
146- end
125+ # Note: `String` takes ownership / removes the body, so we make a copy
126+ body = String (copy (resp. body))
127+ is_primary_rate_limit = occursin (" primary rate limit" , lowercase (body)) && status in (403 , 429 )
128+ is_secondary_rate_limit = occursin (" secondary rate limit" , lowercase (body)) && status in (403 , 429 )
147129
148- # If x-ratelimit-remaining is 0, wait until reset time
149- reset_timestamp = safe_tryparse (Float64, reset_time)
150- if remaining == " 0" && reset_timestamp != = nothing
151- current_time = time ()
152- if reset_timestamp > current_time
153- delay_seconds = reset_timestamp - current_time + 1.0
154- verbose && @info " GitHub API secondary rate limit hit, retrying in $(round (delay_seconds, digits= 1 )) s" method= method status= status limit= limit remaining= remaining used= used reset= reset_time resource= resource retry_after= retry_after
155- return (true , delay_seconds)
156- end
157- end
130+ do_retry = HTTP. RetryRequest. isidempotent (method) && (is_primary_rate_limit || is_secondary_rate_limit || HTTP. RetryRequest. retryable (status))
158131
159- # Otherwise, wait at least 1 minute, then use exponential backoff
160- delay_seconds = max (60.0 , exponential_delay)
161- verbose && @info " GitHub API secondary rate limit hit, retrying in $(round (delay_seconds, digits= 1 )) s" method= method status= status limit= limit remaining= remaining used= used reset= reset_time resource= resource retry_after= retry_after
162- return (true , delay_seconds)
163- else
164- # Primary rate limit handling
165- # If x-ratelimit-remaining is 0, wait until reset time
166- reset_timestamp = safe_tryparse (Float64, reset_time)
167- if remaining == " 0" && reset_timestamp != = nothing
168- current_time = time ()
169- if reset_timestamp > current_time
170- delay_seconds = reset_timestamp - current_time + 1.0
171- verbose && @info " GitHub API primary rate limit hit, retrying in $(round (delay_seconds, digits= 1 )) s" method= method status= status limit= limit remaining= remaining used= used reset= reset_time resource= resource
172- return (true , delay_seconds)
173- end
174- end
132+ if ! do_retry
133+ return (false , 0.0 )
134+ end
175135
176- # For other primary rate limit cases, use exponential backoff
177- verbose && @info " GitHub API primary rate limit hit, retrying in $(round (exponential_delay, digits= 1 )) s" method= method status= status limit= limit remaining= remaining used= used reset= reset_time resource= resource
178- return (true , exponential_delay)
179- end
136+ # Now we know we want to retry. We need to decide how long to wait.
137+
138+ # Get all rate limit headers
139+ limit = HTTP. header (resp, " x-ratelimit-limit" , " " )
140+ remaining = HTTP. header (resp, " x-ratelimit-remaining" , " " )
141+ used = HTTP. header (resp, " x-ratelimit-used" , " " )
142+ reset_time = HTTP. header (resp, " x-ratelimit-reset" , " " )
143+ resource = HTTP. header (resp, " x-ratelimit-resource" , " " )
144+ retry_after = HTTP. header (resp, " retry-after" , " " )
145+
146+ msg = if is_primary_rate_limit
147+ " GitHub API primary rate limit reached"
148+ elseif is_secondary_rate_limit
149+ " GitHub API secondary rate limit reached"
150+ else
151+ " GitHub API returned $status "
152+ end
153+
154+ # If retry-after header is present, respect it
155+ delay_seconds = safe_tryparse (Float64, retry_after)
156+ if delay_seconds != = nothing
157+ delay_seconds = parse (Float64, retry_after)
158+ verbose && @info " $msg , retrying in $(round (delay_seconds, digits= 1 )) s" method= method status= status limit= limit remaining= remaining used= used reset= reset_time resource= resource retry_after= retry_after
159+ return (true , delay_seconds)
180160 end
181161
182- # For other HTTP errors, check if they're retryable according to HTTP.jl
183- if HTTP. RetryRequest. retryable (status) && HTTP. RetryRequest. isidempotent (method)
184- verbose && @info " GitHub API HTTP error, retrying in $(round (exponential_delay, digits= 1 )) s" method= method status= status
185- return (true , exponential_delay)
162+ # If x-ratelimit-remaining is 0, wait until reset time
163+ reset_timestamp = safe_tryparse (Float64, reset_time)
164+ if remaining == " 0" && reset_timestamp != = nothing
165+ current_time = time ()
166+ if reset_timestamp > current_time
167+ delay_seconds = reset_timestamp - current_time + 1.0
168+ verbose && @info " $msg , retrying in $(round (delay_seconds, digits= 1 )) s" method= method status= status limit= limit remaining= remaining used= used reset= reset_time resource= resource retry_after= retry_after
169+ return (true , delay_seconds)
170+ end
186171 end
187172
188- return (false , 0.0 )
173+ # If secondary rate limit hit without headers to guide us,
174+ # make sure we wait at least a minute
175+ delay_seconds = is_secondary_rate_limit ? max (60.0 , exponential_delay) : exponential_delay
176+
177+ # Fall back to exponential backoff
178+ verbose && @info " $msg , retrying in $(round (delay_seconds, digits= 1 )) s" method= method status= status
179+
180+ return (true , delay_seconds)
189181end
190182
191183"""
0 commit comments