Auto-Rename Race-Fix: parallele Scans pro Package serialisieren
Im Production-Log: 21:30:33.957Z Auto-Rename Scan gestartet | videoFiles=25 21:30:33.992Z Auto-Rename Scan gestartet | videoFiles=25 (35ms spaeter, gleiches pkg!) 21:30:33.994Z Auto-Rename durchgefuehrt | E24.B (Scan 1) 21:30:34.009Z Auto-Rename uebersprungen: Ziel existiert (Scan 2 sieht renamed file) 21:30:34.029Z Auto-Rename durchgefuehrt | E24.A (Scan 1) 21:30:34.056Z Auto-Rename fehlgeschlagen | ENOENT (Scan 2 versucht renamed file) Ursache: hybrid-extract feuert nach JEDEM erfolgreichen Archive einen fire-and-forget autoRename (Z.10915), und der deferred Post-Process-Pfad ruft am Ende nochmal autoRename auf (Z.11630). Bei einem Multi-Archive- Package (25 Episoden) ueberlappen sich 2+ Scans auf demselben Fileset. Ergebnis: "Ziel existiert"-Warnungen + ENOENT-Fehler beim Rename. Manchmal blieben einzelne Files unbenannt durchrutschen (Scan 2 sieht File X, will renamen, aber Scan 1 hat es schon weg-renamed). Fix: pro Package via Promise-Chaining serialisieren. Neue Map autoRenameInFlight haelt das laufende Scan-Promise pro packageId. Der neue Wrapper kettet jeden weiteren Aufruf an das vorherige Promise an — so laeuft maximal ein Scan zur Zeit pro Package, der naechste startet erst wenn der vorherige fertig ist (und sieht damit den korrekten Disk-State). Test: zwei parallele autoRenameExtractedVideoFiles-Aufrufe fuer dasselbe Package mit 3 obfuskierten Files. Beide resolven sauber, Summe der Renames == 3, alle 3 Folders enthalten am Ende den korrekten Folder- Namen statt Hoster-Obfuskation. 582/582 Tests gruen.
This commit is contained in:
@@ -1685,6 +1685,18 @@ export class DownloadManager extends EventEmitter {
|
||||
|
||||
private itemContributedBytes = new Map<string, number>();
|
||||
|
||||
/** Per-package serialization for autoRenameExtractedVideoFiles. The hybrid-
|
||||
* extract path fires a fire-and-forget rename after every successful
|
||||
* archive iteration, and the deferred post-process path runs another
|
||||
* rename when post-processing finishes. For a multi-archive package
|
||||
* (e.g. 25 episodes) these can overlap, with two concurrent scans seeing
|
||||
* the same files, racing to rename, and producing "Ziel existiert" /
|
||||
* ENOENT noise plus occasionally missed renames. We chain subsequent
|
||||
* invocations onto the running promise so the second scan re-scans
|
||||
* AFTER the first finishes — picking up any newly-arrived files while
|
||||
* guaranteeing no two scans operate on the same fileset simultaneously. */
|
||||
private autoRenameInFlight = new Map<string, Promise<number>>();
|
||||
|
||||
private runItemIds = new Set<string>();
|
||||
|
||||
private runPackageIds = new Set<string>();
|
||||
@@ -3661,6 +3673,36 @@ export class DownloadManager extends EventEmitter {
|
||||
extractDir: string,
|
||||
pkg?: PackageEntry,
|
||||
shouldAbort?: () => boolean
|
||||
): Promise<number> {
|
||||
// Serialize per-package: chain onto any in-flight scan for the same
|
||||
// package so two scans never read the same fileset in parallel. Without
|
||||
// this, hybrid-extract's per-archive trigger + the deferred post-process
|
||||
// trigger frequently overlap and cause "Ziel existiert" / ENOENT
|
||||
// log noise (and occasionally a missed rename when the second scan's
|
||||
// chosen target file disappears between scan and rename).
|
||||
if (!pkg) {
|
||||
return this.autoRenameExtractedVideoFilesImpl(extractDir, undefined, shouldAbort);
|
||||
}
|
||||
const previous = this.autoRenameInFlight.get(pkg.id);
|
||||
const next = (previous ?? Promise.resolve(0)).catch(() => 0).then(() =>
|
||||
this.autoRenameExtractedVideoFilesImpl(extractDir, pkg, shouldAbort)
|
||||
);
|
||||
this.autoRenameInFlight.set(pkg.id, next);
|
||||
try {
|
||||
return await next;
|
||||
} finally {
|
||||
// Only clear the slot if no newer chained call took our place. This
|
||||
// keeps the chain intact when several callers queue up at once.
|
||||
if (this.autoRenameInFlight.get(pkg.id) === next) {
|
||||
this.autoRenameInFlight.delete(pkg.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async autoRenameExtractedVideoFilesImpl(
|
||||
extractDir: string,
|
||||
pkg?: PackageEntry,
|
||||
shouldAbort?: () => boolean
|
||||
): Promise<number> {
|
||||
if (!this.settings.autoRename4sf4sj) {
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user