Fix: Per-Account-Timeout in Account-Rotation (Mega-Debrid + Debrid-Link)

Kernbug (User-Log, v1.7.168): "Unrestrict Timeout nach 60s" — Account 1 hing die
volle Zeit, acc2/acc3 wurden NIE versucht. Ursache: die gesamte Account-Rotation
lief unter EINEM geteilten ~60s-Signal (download-manager wickelt den ganzen
unrestrictLink in getUnrestrictTimeoutMs()); haengt acc1 bis es feuert, bricht die
ganze Rotation ab.

Fix (debrid.ts): jeder Account/Key bekommt im Rotations-Loop sein EIGENES Timeout
(PER_ACCOUNT_ATTEMPT_TIMEOUT_MS=25s, env RD_PER_ACCOUNT_TIMEOUT_MS, clamp 8-45s) via
AbortController + AbortSignal.any([global, attempt]). Catch: globaler signal.aborted
-> throw (Rotation stoppen); nur attemptController.signal.aborted -> 30s-Cooldown +
naechster Account. Ueber die Retry-Zyklen werden mit den Cooldowns alle Accounts erreicht.

Test: "aborts Mega web unrestrict when caller signal is cancelled" pruefte vorher
Objekt-Identitaet (.toBe(controller.signal)); der Per-Account-Timeout wrappt das Signal
aber zwingend (AbortSignal.any), die gereichte Instanz ist daher absichtlich nicht mehr
identisch. Umgestellt auf VERHALTEN: gereichtes Signal ist eine AbortSignal-Instanz und
propagiert das Caller-Cancel (aborted=true).

Recovered aus dem reset-weggesetzten Commit ae3ee1f (der andere Chat committete den Fix,
der Test brach, er resettete + hing). 641 Tests gruen, tsc unveraendert (9 pre-existing).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sucukdeluxe
2026-05-30 23:37:16 +02:00
co-authored by Claude Opus 4.8
parent 2448ae5c7a
commit c4a49d99ed
2 changed files with 57 additions and 5 deletions
+9 -1
View File
@@ -1386,7 +1386,15 @@ describe("debrid service", () => {
try {
await expect(service.unrestrictLink("https://rapidgator.net/file/abort-mega-web", controller.signal)).rejects.toThrow(/aborted/i);
expect(megaWeb).toHaveBeenCalledTimes(1);
expect(megaWeb.mock.calls[0]?.[1]).toBe(controller.signal);
// Der Rotations-Loop (unrestrictWithAccounts) wickelt das Caller-Signal jetzt
// mit einem Per-Account-Timeout (AbortSignal.any([signal, attemptController.signal])).
// Die an den Web-Unrestrict gereichte Signal-INSTANZ ist daher absichtlich NICHT
// mehr identisch mit controller.signal — entscheidend ist das VERHALTEN: das
// Caller-Cancel propagiert weiterhin durch (das gereichte Signal ist aborted),
// worauf der Web-Unrestrict abbricht. (Bitte nicht zurueck auf .toBe aendern.)
const passedSignal = megaWeb.mock.calls[0]?.[1];
expect(passedSignal).toBeInstanceOf(AbortSignal);
expect(passedSignal?.aborted).toBe(true);
} finally {
clearTimeout(abortTimer);
}