Fix: festes Retry-Limit wird jetzt hart eingehalten — kein Endlos-Shelve-Loop mehr (Runde-6-Audit)
Bei einem FESTEN retryLimit (>=5) sind alle drei Per-Klasse-Retry-Caps (stall/unrestrict/generic) gleich dem Limit. Die beiden "15-Fehler"-Shelve-Zweige (download-manager.ts stall-Pfad + error-Pfad) feuern aber auf der hartkodierten Summe >=15 OBERHALB der Per-Klasse-Terminal-Fail-Pruefungen und HALBIEREN danach alle drei Zaehler. Dadurch wurden die Per-Klasse-Caps nie gleichzeitig ueberschritten: der Eintrag erreichte nie status="failed", schliff endlos im 90s-Takt, item.retries wuchs weit ueber das konfigurierte Limit, der Download-Slot blieb dauerhaft belegt, und das wiederholte providerFailures.delete besiegte immer wieder den Provider-Circuit-Breaker → Hoster-Hammering. resetStaleRetryState konnte nicht eingreifen, weil der <=90s-Re-Admit item.updatedAt frisch haelt (nie 10min stale). Der Auslieferungs-Default retryLimit=0 (= unendlich) ist NICHT betroffen — dort ist der 15-Fehler-Shelve der gewollte Dauer-Park-Backstop und es gibt kein endliches Budget zu verletzen. Fix: in BEIDEN Shelve-Zweigen vor dem queueRetry eine harte Obergrenze — `if (configuredRetryLimit > 0 && item.retries >= configuredRetryLimit)` failt den Eintrag terminal (status="failed", recordRunOutcome, retryStateByItem.delete) statt ihn neu zu queuen. Der ∞-Modus (retryLimit<=0) ueberspringt die Grenze und bleibt unveraendert. Runde-6-Audit (adversarisch verifiziert) hat ausserdem den deferred-LOW-Cluster abgeschlossen: #10 HTTP416-shared-counter, #11 fresh-retry-preempt und #13 queue-wait→elapsedMs sind BENIGN; #12 war genau dieser Bug. Rot-bewiesen: Single-Pass-Integrationstest seedet genericErrorRetries=15 vor und injiziert einen generischen Fehler bei retryLimit=5 → ohne Fix requeued der Shelve (status bleibt nicht "failed"), mit Fix wird terminal gefailt. Volle Suite 882 gruen, tsc unveraendert.
This commit is contained in:
@@ -9165,6 +9165,20 @@ export class DownloadManager extends EventEmitter {
|
||||
const totalFailures = (active.stallRetries || 0) + (active.unrestrictRetries || 0) + (active.genericErrorRetries || 0);
|
||||
if (totalFailures >= 15) {
|
||||
item.retries += 1;
|
||||
if (configuredRetryLimit > 0 && item.retries >= configuredRetryLimit) {
|
||||
item.status = "failed";
|
||||
item.lastError = stallErrorText || "Wiederholt fehlgeschlagen";
|
||||
item.fullStatus = `Fehler: ${item.lastError}`;
|
||||
item.speedBps = 0;
|
||||
item.updatedAt = nowMs();
|
||||
this.recordRunOutcome(item.id, "failed");
|
||||
this.retryStateByItem.delete(item.id);
|
||||
const shelveFailPkgStall = this.session.packages[item.packageId];
|
||||
if (shelveFailPkgStall) this.refreshPackageStatus(shelveFailPkgStall);
|
||||
this.persistSoon();
|
||||
this.emitState();
|
||||
return;
|
||||
}
|
||||
active.stallRetries = Math.floor((active.stallRetries || 0) / 2);
|
||||
active.unrestrictRetries = Math.floor((active.unrestrictRetries || 0) / 2);
|
||||
active.genericErrorRetries = Math.floor((active.genericErrorRetries || 0) / 2);
|
||||
@@ -9351,6 +9365,20 @@ export class DownloadManager extends EventEmitter {
|
||||
const totalNonStallFailures = (active.stallRetries || 0) + (active.unrestrictRetries || 0) + (active.genericErrorRetries || 0);
|
||||
if (totalNonStallFailures >= 15) {
|
||||
item.retries += 1;
|
||||
if (configuredRetryLimit > 0 && item.retries >= configuredRetryLimit) {
|
||||
item.status = "failed";
|
||||
item.lastError = errorText || "Wiederholt fehlgeschlagen";
|
||||
item.fullStatus = `Fehler: ${item.lastError}`;
|
||||
item.speedBps = 0;
|
||||
item.updatedAt = nowMs();
|
||||
this.recordRunOutcome(item.id, "failed");
|
||||
this.retryStateByItem.delete(item.id);
|
||||
const shelveFailPkgErr = this.session.packages[item.packageId];
|
||||
if (shelveFailPkgErr) this.refreshPackageStatus(shelveFailPkgErr);
|
||||
this.persistSoon();
|
||||
this.emitState();
|
||||
return;
|
||||
}
|
||||
active.stallRetries = Math.floor((active.stallRetries || 0) / 2);
|
||||
active.unrestrictRetries = Math.floor((active.unrestrictRetries || 0) / 2);
|
||||
active.genericErrorRetries = Math.floor((active.genericErrorRetries || 0) / 2);
|
||||
|
||||
Reference in New Issue
Block a user