import { o as instrumentPgPool } from "./drive-container-types-CAhznKRr.js";
import { n as errorToInfo, t as createForwardingLogger } from "./forwarding-logger-BBkMSxuJ.js";
import { n as defaultLoadFactory, t as buildWorkerExecutor } from "./build-worker-executor-BqNFZX3J.js";
import { ConsoleLogger } from "document-model";
import { isMainThread, parentPort } from "node:worker_threads";
//#region src/executor/worker/run-worker.ts
const POOL_SAMPLE_INTERVAL_MS = 1e3;
async function defaultCreateDatabase(config, workerId) {
	const { Kysely, PostgresDialect } = await import("kysely");
	const Pool = (await import("pg")).default.Pool;
	const pool = new Pool({
		host: config.host,
		port: config.port,
		database: config.database,
		user: config.user,
		password: config.password,
		ssl: config.ssl ? { rejectUnauthorized: false } : void 0,
		application_name: config.applicationName ?? workerId,
		max: config.poolSize,
		connectionTimeoutMillis: config.connectionTimeoutMillis,
		idleTimeoutMillis: config.idleTimeoutMillis
	});
	const poolInstrumentation = instrumentPgPool(pool, workerId);
	const kysely = new Kysely({ dialect: new PostgresDialect({ pool }) });
	return {
		kysely,
		poolInstrumentation,
		async shutdown() {
			try {
				await kysely.destroy();
			} catch {}
			try {
				await pool.end();
			} catch {}
		}
	};
}
/**
* Drives the worker's message loop. Owns lifecycle of the database handle
* and executor stack. The default factories build a real Postgres pool and
* use dynamic `import()` for model/verifier specs; tests inject overrides
* for an in-process PGlite path.
*/
function runWorker(parentPort, overrides = {}) {
	let workerId = "";
	let initCompleted = false;
	let initConfig = null;
	let executorStack = null;
	let database = null;
	let poolSampleTimer = null;
	let pendingPoolSamples = [];
	let detachPoolListener = null;
	const activeLoadFactory = overrides.loadFactory ?? defaultLoadFactory;
	function post(msg) {
		parentPort.postMessage(msg);
	}
	const logger = createForwardingLogger(post);
	function startPoolReporter(instrumentation) {
		detachPoolListener = instrumentation.onAcquire((durationMs) => {
			pendingPoolSamples.push(durationMs);
		});
		poolSampleTimer = setInterval(() => {
			if (pendingPoolSamples.length === 0) return;
			const durations = pendingPoolSamples;
			pendingPoolSamples = [];
			const stats = instrumentation.getStats();
			post({
				type: "pool-acquire-samples",
				workerId,
				poolName: instrumentation.name,
				timestamp: Date.now(),
				durations,
				size: stats.size,
				idle: stats.idle,
				waiting: stats.waiting
			});
		}, POOL_SAMPLE_INTERVAL_MS);
		poolSampleTimer.unref();
	}
	function stopPoolReporter() {
		if (detachPoolListener) {
			detachPoolListener();
			detachPoolListener = null;
		}
		if (poolSampleTimer) {
			clearInterval(poolSampleTimer);
			poolSampleTimer = null;
		}
		pendingPoolSamples = [];
	}
	process.on("uncaughtException", (err) => {
		try {
			post({
				type: "log",
				level: "error",
				message: "worker uncaughtException",
				args: [errorToInfo(err)],
				timestamp: Date.now()
			});
		} catch {}
		throw err;
	});
	process.on("unhandledRejection", (reason) => {
		try {
			post({
				type: "log",
				level: "error",
				message: "worker unhandledRejection",
				args: [errorToInfo(reason)],
				timestamp: Date.now()
			});
		} catch {}
	});
	async function handleInit(msg) {
		workerId = msg.workerId;
		initConfig = msg;
		database = await (overrides.createDatabase ?? defaultCreateDatabase)(msg.db, msg.workerId);
		if (overrides.beforeBuildExecutor) await overrides.beforeBuildExecutor(database.kysely);
		executorStack = await buildWorkerExecutor({
			init: msg,
			database: database.kysely,
			logger: new ConsoleLogger([`reactor-worker:${msg.workerId}`]),
			loadFactory: activeLoadFactory
		});
		if (database.poolInstrumentation) startPoolReporter(database.poolInstrumentation);
		initCompleted = true;
		logger.info("worker initialized: @workerId", msg.workerId);
		post({
			type: "ready",
			correlationId: msg.correlationId,
			workerId: msg.workerId
		});
	}
	async function handleExecute(correlationId, job) {
		if (!executorStack) {
			post({
				type: "result",
				correlationId,
				result: {
					job,
					success: false
				},
				error: errorToInfo(/* @__PURE__ */ new Error("execute received before init"))
			});
			return;
		}
		try {
			post({
				type: "result",
				correlationId,
				result: await executorStack.executor.executeJob(job),
				writeReady: executorStack.takeLastWriteReady() ?? void 0
			});
		} catch (error) {
			post({
				type: "result",
				correlationId,
				result: {
					job,
					success: false
				},
				error: errorToInfo(error)
			});
		}
	}
	async function handleLoadModel(msg) {
		const stack = executorStack;
		if (!stack) {
			post({
				type: "model-load-failed",
				correlationId: msg.correlationId,
				documentType: msg.model.documentType,
				version: msg.model.version,
				error: errorToInfo(/* @__PURE__ */ new Error("load-model received before init"))
			});
			return;
		}
		let module;
		try {
			module = await activeLoadFactory(msg.model.spec);
		} catch (error) {
			post({
				type: "model-load-failed",
				correlationId: msg.correlationId,
				documentType: msg.model.documentType,
				version: msg.model.version,
				error: errorToInfo(error)
			});
			return;
		}
		const [result] = stack.registry.registerModules(module);
		if (result.status === "error") {
			post({
				type: "model-load-failed",
				correlationId: msg.correlationId,
				documentType: msg.model.documentType,
				version: msg.model.version,
				error: errorToInfo(result.error)
			});
			return;
		}
		post({
			type: "model-loaded",
			correlationId: msg.correlationId,
			documentType: msg.model.documentType,
			version: msg.model.version
		});
	}
	async function shutdownDatabase() {
		stopPoolReporter();
		if (database) await database.shutdown();
	}
	function handleParentMessage(msg) {
		switch (msg.type) {
			case "init":
				handleInit(msg).catch((err) => {
					post({
						type: "log",
						level: "error",
						message: "worker init failed",
						args: [errorToInfo(err)],
						timestamp: Date.now()
					});
				});
				break;
			case "execute":
				if (!initCompleted) {
					logger.warn("received execute before init");
					post({
						type: "result",
						correlationId: msg.correlationId,
						result: {
							job: msg.job,
							success: false
						},
						error: errorToInfo(/* @__PURE__ */ new Error("execute received before init"))
					});
					break;
				}
				handleExecute(msg.correlationId, msg.job).catch((err) => {
					post({
						type: "result",
						correlationId: msg.correlationId,
						result: {
							job: msg.job,
							success: false
						},
						error: errorToInfo(err)
					});
				});
				break;
			case "shutdown":
				logger.info("worker shutting down: @workerId", workerId);
				shutdownDatabase().finally(() => {
					post({
						type: "log",
						level: "info",
						message: "worker shutdown",
						args: [],
						timestamp: Date.now()
					});
					process.exit(0);
				});
				break;
			case "abort":
				logger.warn("abort received (no-op stub): @correlationId", msg.correlationId);
				break;
			case "load-model":
				handleLoadModel(msg).catch((err) => {
					post({
						type: "model-load-failed",
						correlationId: msg.correlationId,
						documentType: msg.model.documentType,
						version: msg.model.version,
						error: errorToInfo(err)
					});
				});
				break;
			default: {
				const raw = msg;
				if (raw["type"] === "__test_throw") {
					const rawReason = raw["reason"];
					const reason = typeof rawReason === "string" ? rawReason : "synthetic uncaughtException";
					setTimeout(() => {
						throw new Error(reason);
					}, 0);
					return;
				}
				break;
			}
		}
	}
	parentPort.on("message", handleParentMessage);
	parentPort.__reactorWorkerHarness = {
		handleParentMessage,
		get initCompleted() {
			return initCompleted;
		},
		get initConfig() {
			return initConfig;
		},
		get workerId() {
			return workerId;
		}
	};
}
//#endregion
//#region src/executor/worker/entry.ts
if (isMainThread || parentPort === null) throw new Error("entry.ts must be run as a worker thread");
runWorker(parentPort);
//#endregion

//# sourceMappingURL=entry.js.map