import { Worker } from "node:worker_threads"; import { performance } from "node:perf_hooks"; import { generateMap } from "../src/mapPipeline.js"; import { createWorldMap } from "../src/worldMap.js"; import { buildMaximumProductionLasso, derivePatchSeed } from "./production-fixtures.mjs"; function assert(condition, message) { if (!condition) throw new Error(message); console.log(`OK: ${message}`); } const initial = generateMap(114514); const world = createWorldMap(initial); const rect = buildMaximumProductionLasso(world); const terrainType = initial.terrainTemplate?.terrainType || initial.terrainDebug?.terrainType || "auto"; const seed = derivePatchSeed(world.seed, terrainType, 0); const worker = new Worker(new URL("./browser-worker-node-shim.mjs", import.meta.url), { type: "module" }); let terminalMessage = null; let cancelStartedAt = 0; let terminationMs = Infinity; let cancellationTriggered = false; const timeout = setTimeout(async () => { try { await worker.terminate(); } catch {} console.error("FAIL: production patch worker did not reach cancellable large-precompute work in time"); process.exit(2); }, 35_000); worker.on("message", async (message) => { if (message.id !== 1) return; if (message.type !== "progress") { terminalMessage = message; return; } const progress = message.progress || {}; if (cancellationTriggered || progress.phase !== "large-candidate-precompute") return; cancellationTriggered = true; // Let the coordinator enter nested-worker work rather than measuring an idle // worker immediately after the phase marker. await new Promise((resolve) => setTimeout(resolve, 100)); cancelStartedAt = performance.now(); await worker.terminate(); terminationMs = performance.now() - cancelStartedAt; clearTimeout(timeout); assert(terminationMs < 500, `production patch Worker termination settles within 500 ms (${terminationMs.toFixed(1)} ms)`); // terminate() is the hard cancellation boundary. No terminal candidate can // be published after it resolves. await new Promise((resolve) => setTimeout(resolve, 25)); assert(terminalMessage === null, "terminated production Worker cannot publish a candidate after cancellation"); console.log("All patch-worker cancellation tests passed."); process.exit(0); }); worker.on("error", async (error) => { clearTimeout(timeout); try { await worker.terminate(); } catch {} console.error(error?.stack || String(error)); process.exit(1); }); worker.postMessage({ id: 1, world, rect, options: { patchMode: "expansion", terrainType, variant: 0, seed, maxQualityRetries: 0, qualityTerrainAttempts: 1, acceptBestAvailableQuality: false, includeSeamVisualization: false, }, search: { searchId: "cancel-integration", operationId: "cancel-integration", committedRevision: 1, workerEpoch: 1, executionAttempt: 1, totalCandidateCount: 1, candidatePlan: [{ candidateId: "cancel:0", candidateOrdinal: 1, variant: 0, seed }], }, });