mirror of
https://github.com/Dvorinka/MyClubServer.git
synced 2026-06-04 02:32:57 +00:00
fix update
This commit is contained in:
@@ -33,6 +33,70 @@ var (
|
||||
cacheTTL = 30 * time.Minute
|
||||
)
|
||||
|
||||
// facrRetryConfig defines retry behavior for FACR API calls
|
||||
var facrRetryConfig = struct {
|
||||
MaxAttempts int
|
||||
BaseDelay time.Duration
|
||||
MaxDelay time.Duration
|
||||
}{
|
||||
MaxAttempts: 10,
|
||||
BaseDelay: 5 * time.Second,
|
||||
MaxDelay: 60 * time.Second,
|
||||
}
|
||||
|
||||
// fetchWithRetry performs HTTP GET with retry logic and exponential backoff
|
||||
func fetchWithRetry(url string, timeout time.Duration) (*http.Response, error) {
|
||||
var lastErr error
|
||||
client := &http.Client{Timeout: timeout}
|
||||
|
||||
for attempt := 1; attempt <= facrRetryConfig.MaxAttempts; attempt++ {
|
||||
resp, err := client.Get(url)
|
||||
if err != nil {
|
||||
lastErr = err
|
||||
if attempt < facrRetryConfig.MaxAttempts {
|
||||
multiplier := 1 << uint(attempt-1) // 2^(attempt-1)
|
||||
delay := facrRetryConfig.BaseDelay * time.Duration(multiplier)
|
||||
if delay > facrRetryConfig.MaxDelay {
|
||||
delay = facrRetryConfig.MaxDelay
|
||||
}
|
||||
time.Sleep(delay)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Check if response indicates an error from the FACR API
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
body, _ := io.ReadAll(io.LimitReader(resp.Body, 2048))
|
||||
resp.Body.Close()
|
||||
|
||||
// Check if body contains scraping error (temporary failure)
|
||||
bodyStr := string(body)
|
||||
if strings.Contains(bodyStr, "scraping failed") ||
|
||||
strings.Contains(bodyStr, "Cloudflare") ||
|
||||
strings.Contains(bodyStr, "failed to fetch") ||
|
||||
resp.StatusCode >= 500 {
|
||||
lastErr = fmt.Errorf("FACR API temporary error (attempt %d): %s", attempt, bodyStr)
|
||||
if attempt < facrRetryConfig.MaxAttempts {
|
||||
multiplier := 1 << uint(attempt-1) // 2^(attempt-1)
|
||||
delay := facrRetryConfig.BaseDelay * time.Duration(multiplier)
|
||||
if delay > facrRetryConfig.MaxDelay {
|
||||
delay = facrRetryConfig.MaxDelay
|
||||
}
|
||||
time.Sleep(delay)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// For other errors, return immediately with a reconstructed response
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("FACR API failed after %d attempts: %v", facrRetryConfig.MaxAttempts, lastErr)
|
||||
}
|
||||
|
||||
func cacheDir() string {
|
||||
return filepath.Join("cache", "facr")
|
||||
}
|
||||
@@ -229,8 +293,7 @@ func (fc *FACRController) SearchClubs(c *gin.Context) {
|
||||
vals.Set("q", q)
|
||||
searchURL := "https://facr.tdvorak.dev/club/search?" + vals.Encode()
|
||||
|
||||
httpClient := &http.Client{Timeout: 60 * time.Second}
|
||||
resp, err := httpClient.Get(searchURL)
|
||||
resp, err := fetchWithRetry(searchURL, 10*time.Minute)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadGateway, gin.H{"error": fmt.Sprintf("Error fetching from FACR API: %v", err)})
|
||||
return
|
||||
@@ -371,8 +434,7 @@ func (fc *FACRController) GetClubInfo(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
external := fmt.Sprintf("https://facr.tdvorak.dev/club/%s/%s", clubType, clubID)
|
||||
httpClient := &http.Client{Timeout: 60 * time.Second}
|
||||
resp, err := httpClient.Get(external)
|
||||
resp, err := fetchWithRetry(external, 10*time.Minute)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadGateway, gin.H{"error": fmt.Sprintf("proxy error: %v", err)})
|
||||
return
|
||||
@@ -639,8 +701,7 @@ func (fc *FACRController) GetClubTables(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
external := fmt.Sprintf("https://facr.tdvorak.dev/club/%s/%s/table", clubType, clubID)
|
||||
httpClient := &http.Client{Timeout: 60 * time.Second}
|
||||
resp, err := httpClient.Get(external)
|
||||
resp, err := fetchWithRetry(external, 10*time.Minute)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadGateway, gin.H{"error": fmt.Sprintf("proxy error: %v", err)})
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user