import { assert } from "../../../shared/src/asserts.js";
import { parse } from "../../../shared/src/valita.js";
import { must } from "../../../shared/src/must.js";
import { parentWorker, singleProcessMode } from "../types/processes.js";
import { exitAfter, runUntilKilled } from "../services/life-cycle.js";
import { getShardConfig } from "../types/shards.js";
import { getNormalizedZeroConfig } from "../config/zero-config.js";
import { createLogContext } from "./logging.js";
import { getOrCreateGauge } from "../observability/metrics.js";
import { initEventSink } from "../observability/events.js";
import { ReplicationStatusPublisher } from "../services/replicator/replication-status.js";
import { ChangeStreamerHttpClient } from "../services/change-streamer/change-streamer-http.js";
import { ThreadWriteWorkerClient } from "../services/replicator/write-worker-client.js";
import { getPragmaConfig, replicaFileModeSchema, setUpMessageHandlers, setupReplica } from "../workers/replicator.js";
import { ReplicatorService } from "../services/replicator/replicator.js";
import { pid } from "node:process";
import { stat } from "node:fs/promises";
//#region ../zero-cache/src/server/replicator.ts
async function runWorker(parent, env, ...args) {
	assert(args.length > 0, `replicator mode not specified`);
	const fileMode = parse(args[0], replicaFileModeSchema);
	const config = getNormalizedZeroConfig({
		env,
		argv: args.slice(1)
	});
	const mode = fileMode === "backup" ? "backup" : "serving";
	const workerName = `${mode}-replicator`;
	const lc = createLogContext(config, { worker: workerName });
	initEventSink(lc, config);
	const { file: dbPath, walMode } = await setupReplica(lc, fileMode, config.replica);
	setupMetrics(lc, dbPath, walMode);
	const pragmas = getPragmaConfig(fileMode);
	const workerClient = new ThreadWriteWorkerClient();
	await workerClient.init(dbPath, mode, pragmas, config.log);
	const runningLocalChangeStreamer = config.changeStreamer.mode === "dedicated" && !config.changeStreamer.uri;
	const shard = getShardConfig(config);
	const { taskID, change, changeStreamer: { port, uri: changeStreamerURI = runningLocalChangeStreamer ? `http://localhost:${port}/` : void 0 } } = config;
	const changeStreamer = new ChangeStreamerHttpClient(lc, shard, change.db, changeStreamerURI);
	const replicator = new ReplicatorService(lc, taskID, `${workerName}-${pid}`, mode, changeStreamer, workerClient, runningLocalChangeStreamer ? ReplicationStatusPublisher.forReplicaFile(dbPath) : null);
	setUpMessageHandlers(lc, replicator, parent);
	const running = runUntilKilled(lc, parent, replicator);
	for await (const _ of replicator.subscribe()) {
		parent.send(["ready", { ready: true }]);
		break;
	}
	return running;
}
function setupMetrics(lc, file, walMode) {
	getOrCreateGauge("replica", "db_size", {
		description: "The size of the replica's main db file, which does not include the wal file(s)",
		unit: "bytes"
	}).addCallback(observeFileSize(lc, file));
	getOrCreateGauge("replica", "wal_size", {
		description: `The size of the replica's wal file`,
		unit: "bytes"
	}).addCallback(observeFileSize(lc, `${file}-wal`));
	if (walMode === "wal2") getOrCreateGauge("replica", "wal2_size", {
		description: `The size of the replica's wal2 file`,
		unit: "bytes"
	}).addCallback(observeFileSize(lc, `${file}-wal2`));
}
function observeFileSize(lc, file) {
	return async (o) => {
		try {
			const stats = await stat(file);
			o.observe(stats.size);
		} catch (e) {
			lc.warn?.(`unable to stat ${file} for size metrics`, e);
		}
	};
}
if (!singleProcessMode()) exitAfter(() => runWorker(must(parentWorker), process.env, ...process.argv.slice(2)));
//#endregion
export { runWorker as default };

//# sourceMappingURL=replicator.js.map