Proactive repairs

This commit is contained in:
Ben Sarmiento
2024-01-07 21:32:01 +01:00
parent 80a1af378a
commit 722ce16537
5 changed files with 89 additions and 18 deletions

View File

@@ -2,6 +2,9 @@ package http
import (
"context"
"encoding/json"
"fmt"
"io"
"math"
"net"
"net/http"
@@ -29,6 +32,20 @@ type HTTPClient struct {
log *logutil.Logger
}
// {
// "error": "infringing_file",
// "error_code": 35
// }
type ErrorResponse struct {
Message string `json:"error"`
Code int `json:"error_code"`
}
func (e *ErrorResponse) Error() string {
return fmt.Sprintf("api response error: %s (code: %d)", e.Message, e.Code)
}
func NewHTTPClient(token string, maxRetries int, timeoutSecs int, cfg config.ConfigInterface, log *logutil.Logger) *HTTPClient {
client := HTTPClient{
bearerToken: token,
@@ -46,22 +63,42 @@ func NewHTTPClient(token string, maxRetries int, timeoutSecs int, cfg config.Con
},
getRetryIncr: func(resp *http.Response, hasRangeHeader bool, err error) int {
if resp != nil {
if resp.StatusCode == 429 || resp.StatusCode == 400 || resp.StatusCode == 403 {
return 1 // retry but don't increment attempt
if resp.StatusCode == 429 {
return 1
}
if resp.StatusCode != http.StatusPartialContent && hasRangeHeader {
return 1
}
return 0 // don't retry
} else if err != nil {
errStr := err.Error()
if strings.Contains(errStr, "EOF") || strings.Contains(errStr, "connection reset") || strings.Contains(errStr, "no such host") {
return 1 // retry but don't increment attempt
} else {
return RATE_LIMIT_FACTOR
log.Errorf("Client request error: %s", err.Error())
if strings.Contains(err.Error(), "api response error") {
if apiErr, ok := err.(*ErrorResponse); ok {
switch apiErr.Code {
case -1: // Internal error
return 1
case 5: // Slow down
return 1
case 6: // Ressource unreachable
return 1
case 17: // Hoster in maintenance
return 1
case 19: // Hoster temporarily unavailable
return 1
case 25: // Service unavailable
return 1
case 34: // Too many requests
return 1
case 36: // Fair Usage Limit
return 1
default:
return 0 // don't retry
}
}
}
return 1
}
return RATE_LIMIT_FACTOR // retry and increment attempt
return RATE_LIMIT_FACTOR
},
cfg: cfg,
ipv6: cmap.New[string](),
@@ -116,6 +153,16 @@ func (r *HTTPClient) Do(req *http.Request) (*http.Response, error) {
attempt := 0
for {
resp, err = r.client.Do(req)
if resp != nil && resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusPartialContent {
body, _ := io.ReadAll(resp.Body)
if body != nil {
var errResp ErrorResponse
jsonErr := json.Unmarshal(body, &errResp)
if jsonErr == nil {
err = &errResp
}
}
}
if incr := r.getRetryIncr(resp, hasRangeHeader, err); incr > 0 {
attempt += incr
if attempt > r.maxRetries {