import { assert } from "../../../shared/src/asserts.js";
import { must } from "../../../shared/src/must.js";
import { DatabaseInitError } from "../../../zqlite/src/db.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 { startOtelAuto } from "./otel-start.js";
import { createLogContext } from "./logging.js";
import { pgClient } from "../types/pg.js";
import { getServerContext } from "../config/server-context.js";
import { deleteLiteDB } from "../db/delete-lite-db.js";
import { warmupConnections } from "../db/warmup.js";
import { initEventSink, publishCriticalEvent } from "../observability/events.js";
import { AutoResetSignal, CHANGE_STREAMER_APP_NAME } from "../services/change-streamer/schema/tables.js";
import { upgradeReplica } from "../services/change-source/common/replica-schema.js";
import { ReplicationStatusPublisher, replicationStatusError } from "../services/replicator/replication-status.js";
import { initializeCustomChangeSource } from "../services/change-source/custom/change-source.js";
import { initializePostgresChangeSource } from "../services/change-source/pg/change-source.js";
import { BackupMonitor } from "../services/change-streamer/backup-monitor.js";
import { ChangeStreamerHttpServer } from "../services/change-streamer/change-streamer-http.js";
import { initializeStreamer } from "../services/change-streamer/change-streamer-service.js";
import { ReplicaMonitor } from "../services/change-streamer/replica-monitor.js";
//#region ../zero-cache/src/server/change-streamer.ts
async function runWorker(parent, env, ...args) {
	assert(args.length > 0, `parent startMs not specified`);
	const parentStartMs = parseInt(args[0]);
	const config = getNormalizedZeroConfig({
		env,
		argv: args.slice(1)
	});
	const { taskID, changeStreamer: { port, address, protocol, startupDelayMs, backPressureLimitHeapProportion, flowControlConsensusPaddingSeconds }, upstream, change, replica, initialSync, litestream } = config;
	startOtelAuto(createLogContext(config, { worker: "change-streamer" }, false));
	const lc = createLogContext(config, { worker: "change-streamer" }, true);
	initEventSink(lc, config);
	const changeDB = pgClient(lc, change.db, {
		max: change.maxConns,
		connection: { ["application_name"]: CHANGE_STREAMER_APP_NAME }
	}, { sendStringAsJson: true });
	warmupConnections(lc, changeDB, "change").catch(() => {});
	const { autoReset, replicationLag } = config;
	const shard = getShardConfig(config);
	let changeStreamer;
	const context = getServerContext(config);
	for (const first of [true, false]) try {
		const { changeSource, subscriptionState } = upstream.type === "pg" ? await initializePostgresChangeSource(lc, upstream.db, shard, replica.file, {
			...initialSync,
			replicationSlotFailover: upstream.pgReplicationSlotFailover
		}, context, replicationLag.reportIntervalMs) : await initializeCustomChangeSource(lc, upstream.db, shard, replica.file, context);
		changeStreamer = await initializeStreamer(lc, shard, taskID, address, protocol, changeDB, changeSource, ReplicationStatusPublisher.forReplicaFile(replica.file), subscriptionState, autoReset ?? false, backPressureLimitHeapProportion, flowControlConsensusPaddingSeconds, setTimeout);
		break;
	} catch (e) {
		if (first && e instanceof AutoResetSignal) {
			lc.warn?.(`resetting replica ${replica.file}`, e);
			deleteLiteDB(replica.file);
			continue;
		}
		await publishCriticalEvent(lc, replicationStatusError(lc, "Initializing", e));
		if (e instanceof DatabaseInitError) throw new Error(`Cannot open ZERO_REPLICA_FILE at "${replica.file}". Please check that the path is valid.`, { cause: e });
		throw e;
	}
	assert(changeStreamer, `resetting replica did not advance replicaVersion`);
	await upgradeReplica(lc, "change-streamer-init", replica.file);
	const { backupURL, port: metricsPort } = litestream;
	const monitor = backupURL ? new BackupMonitor(lc, replica.file, backupURL, `http://localhost:${metricsPort}/metrics`, changeStreamer, Date.now() - parentStartMs) : new ReplicaMonitor(lc, replica.file, changeStreamer);
	const changeStreamerWebServer = new ChangeStreamerHttpServer(lc, config, {
		port,
		startupDelayMs
	}, parent, changeStreamer, monitor instanceof BackupMonitor ? monitor : null);
	parent.send(["ready", { ready: true }]);
	return runUntilKilled(lc, parent, changeStreamerWebServer, monitor);
}
if (!singleProcessMode()) exitAfter(() => runWorker(must(parentWorker), process.env, ...process.argv.slice(2)));
//#endregion
export { runWorker as default };

//# sourceMappingURL=change-streamer.js.map