fix(extraction): coordinate jobs leases and shutdown

Route full, hybrid, top-level nested, and deferred nested archive work through the single global coordinator and remove the package-level extraction slot layer. Build each operation reservation from deduplicated multipart members, retain it through real child close and package output-scope finalization, and preserve package/run cancellation ownership while clearing queued waiters. Delay native and JVM abort/timeout completion until child close, retain daemon requests until exit, drain extraction before session persistence, and stop the daemon last. Add focused integration, process lifecycle, lease, and shutdown ordering regression coverage.
This commit is contained in:
Sucukdeluxe
2026-08-22 16:54:41 +02:00
parent 36eaafd5b9
commit 648e7fed3a
10 changed files with 667 additions and 382 deletions
+31
View File
@@ -331,4 +331,35 @@ describe("ExtractionCoordinator", () => {
await Promise.all([active, finalized, shutdown]);
expect(events).toEqual(["waiter-cancel", "active-abort", "child-close", "scope-finalize", "lease-release"]);
});
it("waits for scope finalization registered immediately after child drain", async () => {
const coordinator = new ExtractionCoordinator(1);
const heldLease = lease();
const operation = await coordinator.beginOperation({
context: context("late-finalize", "package-a", "run"),
targetPath: "C:\\target",
members: [{ path: "C:\\archives\\one.rar", size: 100 }],
acquireLease: async () => heldLease
});
const childClose = deferred<void>();
const scopeClose = deferred<void>();
const active = coordinator.scheduleArchive(operation, "active", async () => childClose.promise);
let shutdownSettled = false;
const shutdown = coordinator.shutdownAndDrain(Date.now() + 1000).then(() => {
shutdownSettled = true;
});
childClose.resolve();
await active;
await new Promise<void>((resolve) => setTimeout(resolve, 0));
expect(shutdownSettled).toBe(false);
const finalization = operation.finalize(async () => scopeClose.promise);
await new Promise<void>((resolve) => setTimeout(resolve, 0));
expect(shutdownSettled).toBe(false);
expect(heldLease.release).not.toHaveBeenCalled();
scopeClose.resolve();
await Promise.all([finalization, shutdown]);
expect(heldLease.release).toHaveBeenCalledTimes(1);
});
});