fix: preserve delivered folder reservations

This commit is contained in:
Sucukdeluxe
2026-08-26 09:46:44 +02:00
parent 7890292d96
commit 2063599611
2 changed files with 39 additions and 3 deletions
+6 -3
View File
@@ -227,11 +227,14 @@ class FolderMonitor extends EventEmitter {
const files = this._batchBuffer.splice(0);
this._batchTimer = null;
if (files.length === 0) return;
const listenerError = this._emitEvent('new-files', [files], generation);
const dispatchSeenReservations = new Set();
for (const emittedPath of files) {
const emittedNormalized = this._normalizePath(emittedPath);
if (!this._batchSeenReservations.delete(emittedNormalized)) continue;
if (listenerError) this._seenFiles.delete(emittedNormalized);
if (this._batchSeenReservations.delete(emittedNormalized)) dispatchSeenReservations.add(emittedNormalized);
}
const listenerError = this._emitEvent('new-files', [files], generation);
if (listenerError) {
for (const emittedNormalized of dispatchSeenReservations) this._seenFiles.delete(emittedNormalized);
}
if (listenerError && this._acceptCallback(generation)) {
this._lastError = 'Ordnerüberwachung fehlgeschlagen';
+33
View File
@@ -374,6 +374,39 @@ test('watcher add paused before batch timeout is emitted exactly once by resume
assert.equal(monitor.status().seenCount, 1);
});
test('synchronous pause during successful batch emission does not duplicate on resume', async () => {
const timers = createManualTimers();
const watchers = [];
const newFiles = [];
const filePath = 'C:\\watch\\delivered.mkv';
let pausePromise;
const monitor = new FolderMonitor({
watch: () => {
const watcher = new EventEmitter();
watcher.close = async () => {};
watchers.push(watcher);
return watcher;
},
access: async () => {},
walkFolder: async () => [{ path: filePath, name: 'delivered.mkv', size: 1 }],
stat: async () => ({ mtimeMs: 1 }),
...timers
});
monitor.on('new-files', (files) => {
newFiles.push(files);
pausePromise = monitor.pause();
});
const settings = { folderPath: 'C:\\watch', extensions: 'mkv', skipDuplicates: true, reconcileIntervalMinutes: 5 };
monitor.start(settings);
watchers[0].emit('add', filePath);
await timers.runTimeouts();
await pausePromise;
assert.deepEqual(newFiles, [[filePath]]);
await monitor.resume(settings);
assert.deepEqual(newFiles, [[filePath]]);
assert.equal(monitor.status().seenCount, 1);
});
test('pause rollback never deletes historical seen state from a dedupe-off batch', async () => {
const timers = createManualTimers();
const watchers = [];