Skip to content

Commit b5b1d05

Browse files
author
ciroautuori
committed
docs: update README with network-error circuit breaker, 504 handling, and health check skip for invalid keys
1 parent 4c70a41 commit b5b1d05

1 file changed

Lines changed: 15 additions & 7 deletions

File tree

‎README.md‎

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,13 @@ openvidia
9898
│ │ │ cooldown? RPM < 28? │ │
9999
│ │ │ skip if yes skip if no │ │
100100
│ │ │ │ │
101-
│ │ On 429: read Retry-After → set cooldown → next key │ │
101+
│ │ On 429: read Retry-After → set cooldown → next key │ │
102102
│ │ On 401/403: cooldown 3600s (dead key) │ │
103103
│ │ On 400/404: cooldown 60s (deterministic) │ │
104+
│ │ On 504: cooldown 30s (model bottleneck, not key) │ │
104105
│ │ On 5xx: cooldown 10s (gateway) / 30s (other) │ │
106+
│ │ On network error: no cooldown, 0.5s pause │ │
107+
│ │ 3 consecutive network errors → stop (network down)│ │
105108
│ └─────────────────────────────────────────────────────┘ │
106109
│ │ │
107110
│ NVIDIA NIM API │
@@ -118,8 +121,10 @@ NVIDIA's free NIM tier limits each API key to ~40 RPM. Aggressive bursts trigger
118121
- **Pools multiple keys** behind a single endpoint
119122
- **Rotates automatically** on 429/401/403/5xx — zero manual intervention
120123
- **Per-key cooldown timers** — on real 429s, trusts `Retry-After` exactly (no multiplication); distinguishes transient worker saturation (`ResourceExhausted`) from true RPM limits and never burns key cooldowns for the former
124+
- **Network-error circuit breaker** — `ConnectTimeout`/`ConnectError` don't trigger key cooldown (the key is fine). After 3 consecutive network errors across different keys, rotation stops entirely and returns 503 (the network is down, no key can help)
125+
- **504 model timeouts don't burn keys** — gateway timeouts cool the key for 30s but don't consume the attempt budget, since the model (not the key) is the bottleneck
121126
- **Sliding-window RPM limiting** — keeps each key under 28 RPM (safe margin below 40)
122-
- **Health checks** — revives keys whose cooldowns have expired
127+
- **Health checks** — revives keys whose cooldowns have expired, but skips 401/403 invalid keys (dead keys stay dead)
123128
- **No silent model substitution** — the model you select is the model that answers; if it fails on every key you are told so, never handed output from a different model
124129
- **Auto-compaction** — summarizes long histories so requests never fail on context overflow ([details](#auto-compaction))
125130

@@ -316,8 +321,9 @@ Streaming (SSE) is fully supported — tokens flow through unbuffered.
316321
| **429** (worker concurrency) | 0 — retried after 0.8s pause | `ResourceExhausted: Worker local total request limit reached` — transient pool saturation, key is healthy |
317322
| **401 / 403** | 3600s | Dead key — don't waste requests |
318323
| **400 / 404** | 60s | Deterministic request error — short cooldown, key untouched for rotation. Every key gets the same error, so rotating only burns cooldown budget. |
319-
| **5xx** | 10s (502/503/504 gateway timeout) / 30s (500 other) | Server error — retry soon |
320-
| **Network error** | 30s | Transient connectivity issue |
324+
| **504** (gateway timeout) | 30s | Model is the bottleneck, not the key — longer cooldown, but doesn't burn the attempt budget |
325+
| **5xx** (other) | 10s (502/503) / 30s (500) | Server error — retry soon |
326+
| **Network error** (ConnectTimeout/ConnectError) | 0 — 0.5s pause, no cooldown | Network is down, not the key. After 3 consecutive errors across different keys, rotation stops entirely (503). |
321327
322328
> **Retry-After is used as-is.** When NVIDIA provides a `Retry-After` header (e.g. 60s), the cooldown is exactly that value. Earlier versions multiplied it by an adaptive factor (`1.5^N`), which caused a doom loop: at 3 failures a 60s backoff became 135s and all 26 keys locked out longer than the real rate-limit window required.
323329
>
@@ -339,8 +345,10 @@ Request arrives
339345
│ │ → 400/404? set 60s cooldown, next key
340346
│ │ → 429 ResourceExhausted? pause 0.8s, retry (key untouched)
341347
│ │ → 429 rate-limit? use Retry-After as-is, set cooldown, next key
342-
│ │ → 401? set 3600s cooldown, next key
343-
│ │ → 5xx? set 10s (502/503/504) or 30s (other), next key
348+
│ │ → 401/403? set 3600s cooldown, next key
349+
│ │ → 504? set 30s cooldown, next key (doesn't burn attempt budget)
350+
│ │ → 5xx? set 10s (502/503) or 30s (500), next key
351+
│ │ → network error? 0.5s pause, key untouched (3 consecutive → stop)
344352
│ └─ (max 5 sends per pass, 3 passes with 1s pause between)
345353
│
346354
└─ All candidates exhausted? → 503 naming the model (never a substitute model)
@@ -349,7 +357,7 @@ Request arrives
349357
### Health Check
350358
351359
Every 60 seconds:
352-
1. Finds keys still on cooldown
360+
1. Finds keys still on cooldown (skips 401/403 invalid keys — they're dead, not temporarily rate-limited)
353361
2. Sends a lightweight `GET /v1/models` probe
354362
3. If the key responds OK — clears the cooldown (revived)
355363
4. If still failing — leaves the cooldown in place

0 commit comments

Comments
 (0)