Debrid-Link stability: stop double-blocking, shorter transport cooldown, max-wins
User reported Debrid-Link "often jumps into provider-cooldown" and feels unstable. Root cause was four cooperating bugs that turned isolated key-level failures into provider-wide multi-minute outages. Fix 1: Skip provider-wide circuit breaker for ALL Debrid-Link errors (download-manager.ts ~8689) Previously only the explicit `debrid_link_cooldown:` sentinel was bypassed; every other Debrid-Link error (terminal failures, timeouts, parse errors) still went through recordProviderFailure() + applyProviderBusyBackoff(), applying a provider-wide cooldown ON TOP of the per-key cooldown debrid.ts already managed. Now any error message containing "debrid-link" or where the failure key is "debridlink" skips the provider-level circuit breaker entirely. Per-key cooldowns alone are the right granularity. Fix 2: Transport errors get a short 15s cooldown, not 2 min (debrid.ts ~2684) A single network timeout / ECONNRESET was parking the key for 2 full minutes. With 9 keys all of which might experience the same transient issue at different moments, this could cascade into all keys cooling down for 2 min each. Now isolated transport hiccups get 15s while real API/server problems still get the full 2 min. Fix 3: HTTP 200 with success:false (no error code) is now temporary, not fatal (debrid.ts ~2691) Previously these went through to the fallthrough "fatal: true" which permanently failed the item. Now they get a 30s temporary cooldown and the item retries on the next key. Fix 4: setDebridLinkKeyCooldownState is max-wins under concurrent calls (debrid.ts ~135) When 8 parallel items all hit the same key with floodDetected, each computes its own cooldown duration and calls setDebrid LinkKeyCooldown State. Without max-wins, the LAST setter could shorten the cooldown (e.g. one item read a 1h Retry-After header, another defaulted to 2 min; the 2 min would then overwrite the 1h). Now the longer cooldown wins, with rate_limit/quota/invalid categories also winning over plain temporary regardless of duration. Tests: 201/201 (debrid + download-manager) green. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
7be2d2e148
commit
cdec0029fe
@@ -8687,12 +8687,21 @@ export class DownloadManager extends EventEmitter {
|
||||
active.unrestrictRetries += 1;
|
||||
item.retries += 1;
|
||||
const failureProvider = this.getProviderFailureKeyForItem(item);
|
||||
this.recordProviderFailure(failureProvider);
|
||||
if (isProviderBusyUnrestrictError(errorText) || isTemporaryUnrestrictError(errorText)) {
|
||||
const busyCooldownMs = isTemporaryUnrestrictError(errorText)
|
||||
? Math.min(180000, 20000 + Number(active.unrestrictRetries || 0) * 10000)
|
||||
: Math.min(60000, 12000 + Number(active.unrestrictRetries || 0) * 3000);
|
||||
this.applyProviderBusyBackoff(failureProvider, busyCooldownMs);
|
||||
// Debrid-Link manages its own per-key cooldowns in debrid.ts. The
|
||||
// provider-wide circuit breaker would double-block all Debrid-Link
|
||||
// keys when only one key (or a transient transport hiccup) failed.
|
||||
// Skip recordProviderFailure / applyProviderBusyBackoff entirely
|
||||
// for any Debrid-Link-flavoured error message, not just the
|
||||
// debrid_link_cooldown sentinel that's caught above.
|
||||
const isDebridLinkError = /debrid-link|debrid_link/i.test(errorText) || failureProvider === "debridlink";
|
||||
if (!isDebridLinkError) {
|
||||
this.recordProviderFailure(failureProvider);
|
||||
if (isProviderBusyUnrestrictError(errorText) || isTemporaryUnrestrictError(errorText)) {
|
||||
const busyCooldownMs = isTemporaryUnrestrictError(errorText)
|
||||
? Math.min(180000, 20000 + Number(active.unrestrictRetries || 0) * 10000)
|
||||
: Math.min(60000, 12000 + Number(active.unrestrictRetries || 0) * 3000);
|
||||
this.applyProviderBusyBackoff(failureProvider, busyCooldownMs);
|
||||
}
|
||||
}
|
||||
// Escalating backoff: 5s, 7.5s, 11s, 17s, 25s, 38s, ... up to 120s
|
||||
let unrestrictDelayMs = Math.min(120000, Math.floor(5000 * Math.pow(1.5, active.unrestrictRetries - 1)));
|
||||
|
||||
Reference in New Issue
Block a user