-
Notifications
You must be signed in to change notification settings - Fork 34
Open
Labels
Description
Problem
The Gateway calls OpenRouter via a standard http.DefaultClient.
If OpenRouter experiences downtime, high latency, or intermittent failures, the Gateway will:
- Hang until the 30s timeout, tying up resources.
- Spam the failing API repeatedly, worsening the issue.
- Fail immediately on transient network blips without retrying.
stateDiagram-v2
[*] --> Closed
Closed --> Open : Failure Threshold Reached
Open --> HalfOpen : Timeout Expired
HalfOpen --> Closed : Success
HalfOpen --> Open : Failure
state Closed {
[*] --> Request
Request --> Success
Request --> Failure
}
state Open {
[*] --> FastFail
}
Solution
Implement the Circuit Breaker pattern (to stop calling a dead service) and Exponential Backoff Retries (for transient errors).
Implementation
- Add dependency:
github.com/sony/gobreaker - Wrap
callOpenRouterlogic:
var cb *gobreaker.CircuitBreaker
func init() {
cb = gobreaker.NewCircuitBreaker(gobreaker.Settings{
Name: "OpenRouter",
MaxRequests: 5,
Timeout: 30 * time.Second,
ReadyToTrip: func(counts gobreaker.Counts) bool {
return counts.ConsecutiveFailures > 3
},
})
}Acceptance Criteria
- Gateway stops calling OpenRouter after 3 consecutive failures (Circuit Open)
- Gateway returns "503 Service Unavailable" immediately when Circuit is Open
- Gateway retries 500/502/503 responses from OpenRouter up to 3 times
- Gateway recovers automatically (Half-Open -> Closed)
Testing
- Mock OpenRouter to return 500s -> Verify Circuit Open.
- Mock OpenRouter to return success after 1 failure -> Verify Retry success.
Reactions are currently unavailable