Refactor should retry

This commit is contained in:
Ben Adrian Sarmiento
2024-07-11 16:36:03 +02:00
parent 396a8781aa
commit b0363edbbb

View File

@@ -181,13 +181,11 @@ func (r *HTTPClient) Do(req *http.Request) (*http.Response, error) {
} }
} }
incr := r.shouldRetry(req, resp, err, attempt, r.rateLimitSleepSecs) if !r.shouldRetry(req, resp, err, attempt, r.rateLimitSleepSecs) {
if incr == -1 {
break break
} else if incr == 0 {
continue
} }
attempt += incr attempt++
continue
} }
return resp, err return resp, err
} }
@@ -240,53 +238,56 @@ func (r *HTTPClient) proxyDialer(proxyURL *url.URL) (proxy.Dialer, error) {
return nil, fmt.Errorf("unsupported proxy scheme: %s", proxyURL.Scheme) return nil, fmt.Errorf("unsupported proxy scheme: %s", proxyURL.Scheme)
} }
// shouldRetry returns a number indicating whether the request should be retried // shouldRetry returns true if the request should be retried
// -1: don't retry func (r *HTTPClient) shouldRetry(req *http.Request, resp *http.Response, err error, attempts, rateLimitSleep int) bool {
// 0: retry indefinitely
// 1: retry until maxRetries
func (r *HTTPClient) shouldRetry(req *http.Request, resp *http.Response, err error, attempts, rateLimitSleep int) int {
if attempts >= r.maxRetries {
return -1
}
// assume that all addMagnet requests are always successful; // assume that all addMagnet requests are always successful;
// don't retry to prevent duplicate torrents // don't retry to prevent duplicate torrents
if req.Host == "api.real-debrid.com" && strings.HasSuffix(req.URL.Path, "torrents/addMagnet") { if req.Host == "api.real-debrid.com" && strings.HasSuffix(req.URL.Path, "torrents/addMagnet") {
return -1 return false
} }
if apiErr, ok := err.(*ApiErrorResponse); ok { if apiErr, ok := err.(*ApiErrorResponse); ok {
switch apiErr.Code { switch apiErr.Code {
case 5: // Slow down (retry infinitely) case 5: // Slow down (retry infinitely)
secs := r.backoff(attempts, rateLimitSleep) secs := r.backoff(attempts, rateLimitSleep)
r.log.Debugf("API rate limit reached, retrying in %d seconds", secs/time.Second) r.log.Debugf("API rate limit reached, attempt #%d, retrying in %d seconds", attempts+1, secs/time.Second)
time.Sleep(secs) time.Sleep(secs)
return 0 return true
case 34: // Too many requests (retry infinitely) case 34: // Too many requests (retry infinitely)
secs := r.backoff(attempts, rateLimitSleep) secs := r.backoff(attempts, rateLimitSleep)
r.log.Debugf("API rate limit reached, retrying in %d seconds", secs/time.Second) r.log.Debugf("API rate limit reached, attempt #%d, retrying in %d seconds", attempts+1, secs/time.Second)
time.Sleep(secs) time.Sleep(secs)
return 0 return true
case 36: // Fair Usage Limit case 36: // Fair Usage Limit
secs := r.backoff(attempts, rateLimitSleep) secs := r.backoff(attempts, rateLimitSleep)
r.log.Debugf("Fair usage limit reached, retrying in %d seconds", secs/time.Second) r.log.Debugf("Fair usage limit reached, attempt #%d, retrying in %d seconds", attempts+1, secs/time.Second)
time.Sleep(secs) time.Sleep(secs)
return 0 return true
case -1: // Internal error case -1: // Internal error
r.log.Debugf("RD Internal error, attempt #%d, retrying", attempts+1) if attempts >= r.maxRetries {
return 1 r.log.Debugf("RD Internal error, attempt #%d", attempts+1)
return false
}
secs := r.backoff(attempts, 1)
r.log.Debugf("RD Internal error, attempt #%d, retrying in %d seconds", attempts+1, secs/time.Second)
time.Sleep(secs)
return true
default: default:
return -1 return false
} }
} else if downloadErr, ok := err.(*DownloadErrorResponse); ok { } else if downloadErr, ok := err.(*DownloadErrorResponse); ok {
switch downloadErr.Message { switch downloadErr.Message {
case "invalid_download_code": // 404 case "invalid_download_code": // 404
if attempts >= r.maxRetries {
r.log.Debugf("Invalid download code, attempt #%d", attempts+1)
return false
}
secs := r.backoff(attempts, rateLimitSleep) secs := r.backoff(attempts, rateLimitSleep)
r.log.Debugf("Invalid download code, attempt #%d, retrying in %d seconds", attempts+1, secs/time.Second) r.log.Debugf("Invalid download code, attempt #%d, retrying in %d seconds", attempts+1, secs/time.Second)
time.Sleep(r.backoff(attempts, rateLimitSleep)) time.Sleep(secs)
return 1 return true
default: default:
return -1 return false
} }
} }
@@ -296,13 +297,19 @@ func (r *HTTPClient) shouldRetry(req *http.Request, resp *http.Response, err err
// if the request has a Range header but the server doesn't respond with a Content-Range header // if the request has a Range header but the server doesn't respond with a Content-Range header
hasRangeHeader := req.Header.Get("Range") != "" && !strings.HasPrefix(req.Header.Get("Range"), "bytes=0-") hasRangeHeader := req.Header.Get("Range") != "" && !strings.HasPrefix(req.Header.Get("Range"), "bytes=0-")
if okResponseCode && hasRangeHeader && resp.Header.Get("Content-Range") == "" { if okResponseCode && hasRangeHeader && resp.Header.Get("Content-Range") == "" {
return 0 return true
} }
return -1 return false
} }
r.log.Debugf("Request failed, attempt #%d, retrying (error=%v)", attempts+1, err) if attempts >= r.maxRetries {
return 1 r.log.Debugf("Request failed, attempt #%d (error=%v)", attempts+1, err)
return false
}
secs := r.backoff(attempts, 1)
r.log.Debugf("Request failed, attempt #%d, retrying in %d seconds (error=%v)", attempts+1, secs/time.Second, err)
time.Sleep(secs)
return true
} }
func backoffFunc(attempt, base int) time.Duration { func backoffFunc(attempt, base int) time.Duration {