mirror of
https://github.com/lukaszraczylo/graphql-monitoring-proxy.git
synced 2026-10-20 06:28:13 +00:00
fix(tests): configurable retry delays and circuit backoff overflow
Three bugs fixed: 1. **Test suite timeout** — The main-package test suite timed out at 120s because each failing request triggered 7 retries with exponential backoff (500ms base → 10s max ≈ 25.5s per request). Tests that trip the circuit breaker (3 requests × 25.5s = 76.5s) plus TestStartHTTPProxy_ErrorHandlerConfigured (another 25.5s) pushed cumulative time past the limit. Fix: add `Client.RetryBaseDelayMs` / `Client.RetryMaxDelayMs` config fields (env: CLIENT_RETRY_BASE_DELAY_MS / CLIENT_RETRY_MAX_DELAY_MS, defaults 500ms / 10000ms). Tests override these to 10ms so retry exhaustion completes in milliseconds. Full suite now runs in ~35s. 2. **effectiveCircuitBackoff float overflow** — On amd64, converting `+Inf` (float64) to `time.Duration` (int64) saturates to MinInt64, not MaxInt64. The existing "< base" guard then returned `base` instead of `maxSaneCircuitBackoff`, breaking the sanity ceiling for an uncapped config with a high trip count. Fix: detect `math.IsInf / math.IsNaN` before the cast and return the ceiling directly. 3. **TestStartHTTPProxy_ErrorHandlerConfigured** — standalone top-level test calling parseConfig() directly, bypassing the TestSuite override. Now sets and restores RetryBaseDelayMs/RetryMaxDelayMs explicitly. Co-authored-by: lukaszraczylo <[email protected]>
This commit is contained in:
co-authored by
lukaszraczylo
parent
aaa08dfbb2
commit
8d1518b961
@@ -477,7 +477,16 @@ func effectiveCircuitBackoff(base time.Duration, multiplier float64, maxBackoff
|
||||
}
|
||||
|
||||
exponent := float64(trips - 1)
|
||||
effective := time.Duration(float64(base) * math.Pow(multiplier, exponent))
|
||||
raw := float64(base) * math.Pow(multiplier, exponent)
|
||||
|
||||
// On amd64 the float64->int64 conversion for +Inf saturates to MinInt64
|
||||
// rather than MaxInt64, so the subsequent "< base" guard would return base
|
||||
// instead of the hard ceiling. Detect overflow before the cast.
|
||||
if math.IsInf(raw, 1) || math.IsNaN(raw) {
|
||||
return maxSaneCircuitBackoff
|
||||
}
|
||||
|
||||
effective := time.Duration(raw)
|
||||
if effective < base {
|
||||
// Overflow or float rounding pushed us below base; never shorten.
|
||||
return base
|
||||
@@ -937,17 +946,31 @@ func performProxyRequestWithEnhancedRetries(c fiber.Ctx, proxyURL string, backen
|
||||
var initialDelay time.Duration
|
||||
var maxDelayTime time.Duration
|
||||
|
||||
// Read per-request base and max delay from config; fall back to coded
|
||||
// defaults when zero (e.g. during very early startup before parseConfig).
|
||||
baseDelayMs := cfg.Client.RetryBaseDelayMs
|
||||
if baseDelayMs <= 0 {
|
||||
baseDelayMs = 500
|
||||
}
|
||||
maxDelayMs := cfg.Client.RetryMaxDelayMs
|
||||
if maxDelayMs <= 0 {
|
||||
maxDelayMs = 10000
|
||||
}
|
||||
|
||||
if backendUnhealthy {
|
||||
// Backend is known to be unhealthy, fail fast
|
||||
// Circuit breaker should handle this, so reduce retries
|
||||
attempts = 3
|
||||
initialDelay = 500 * time.Millisecond
|
||||
maxDelayTime = 5 * time.Second
|
||||
initialDelay = time.Duration(baseDelayMs) * time.Millisecond
|
||||
maxDelayTime = time.Duration(maxDelayMs/2) * time.Millisecond
|
||||
if maxDelayTime < initialDelay {
|
||||
maxDelayTime = initialDelay
|
||||
}
|
||||
} else {
|
||||
// Normal retry strategy
|
||||
attempts = 7
|
||||
initialDelay = 500 * time.Millisecond
|
||||
maxDelayTime = 10 * time.Second
|
||||
initialDelay = time.Duration(baseDelayMs) * time.Millisecond
|
||||
maxDelayTime = time.Duration(maxDelayMs) * time.Millisecond
|
||||
}
|
||||
|
||||
return retry.Do(
|
||||
|
||||
Reference in New Issue
Block a user