@rocicorp/zero 0.25.13-canary.6 → 0.25.13-canary.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/out/zero/package.json.js +1 -1
  2. package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
  3. package/out/zero-cache/src/server/change-streamer.js +3 -0
  4. package/out/zero-cache/src/server/change-streamer.js.map +1 -1
  5. package/out/zero-cache/src/server/main.d.ts.map +1 -1
  6. package/out/zero-cache/src/server/main.js +6 -0
  7. package/out/zero-cache/src/server/main.js.map +1 -1
  8. package/out/zero-cache/src/server/runner/run-worker.d.ts.map +1 -1
  9. package/out/zero-cache/src/server/runner/run-worker.js +7 -3
  10. package/out/zero-cache/src/server/runner/run-worker.js.map +1 -1
  11. package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
  12. package/out/zero-cache/src/server/syncer.js +3 -0
  13. package/out/zero-cache/src/server/syncer.js.map +1 -1
  14. package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +1 -1
  15. package/out/zero-cache/src/services/change-source/pg/change-source.js +69 -4
  16. package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
  17. package/out/zero-cache/src/services/change-source/pg/decommission.d.ts.map +1 -1
  18. package/out/zero-cache/src/services/change-source/pg/decommission.js +18 -3
  19. package/out/zero-cache/src/services/change-source/pg/decommission.js.map +1 -1
  20. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts.map +1 -1
  21. package/out/zero-cache/src/services/change-source/pg/initial-sync.js +31 -1
  22. package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
  23. package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +1 -1
  24. package/out/zero-cache/src/services/change-streamer/storer.js +12 -1
  25. package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
  26. package/out/zero-cache/src/services/litestream/commands.d.ts.map +1 -1
  27. package/out/zero-cache/src/services/litestream/commands.js +9 -0
  28. package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
  29. package/out/zero-client/src/client/version.js +1 -1
  30. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- const version = "0.25.13-canary.6";
1
+ const version = "0.25.13-canary.9";
2
2
  const packageJson = {
3
3
  version
4
4
  };
@@ -1 +1 @@
1
- {"version":3,"file":"change-streamer.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/server/change-streamer.ts"],"names":[],"mappings":"AAkBA,OAAO,EAGL,KAAK,MAAM,EACZ,MAAM,uBAAuB,CAAC;AAK/B,wBAA8B,SAAS,CACrC,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,CAAC,UAAU,EACtB,GAAG,IAAI,EAAE,MAAM,EAAE,GAChB,OAAO,CAAC,IAAI,CAAC,CAsHf"}
1
+ {"version":3,"file":"change-streamer.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/server/change-streamer.ts"],"names":[],"mappings":"AAkBA,OAAO,EAGL,KAAK,MAAM,EACZ,MAAM,uBAAuB,CAAC;AAK/B,wBAA8B,SAAS,CACrC,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,CAAC,UAAU,EACtB,GAAG,IAAI,EAAE,MAAM,EAAE,GAChB,OAAO,CAAC,IAAI,CAAC,CA2Hf"}
@@ -35,6 +35,9 @@ async function runWorker(parent, env, ...args) {
35
35
  startOtelAuto(createLogContext(config, { worker: "change-streamer" }, false));
36
36
  const lc = createLogContext(config, { worker: "change-streamer" }, true);
37
37
  initEventSink(lc, config);
38
+ lc.info?.(
39
+ `replication-manager litestream backupURL=${config.litestream.backupURL ?? "(none)"} replicaFile=${config.replica.file}`
40
+ );
38
41
  const changeDB = pgClient(lc, change.db, {
39
42
  max: change.maxConns,
40
43
  connection: { ["application_name"]: "zero-change-streamer" }
@@ -1 +1 @@
1
- {"version":3,"file":"change-streamer.js","sources":["../../../../../zero-cache/src/server/change-streamer.ts"],"sourcesContent":["import {assert} from '../../../shared/src/asserts.ts';\nimport {must} from '../../../shared/src/must.ts';\nimport {DatabaseInitError} from '../../../zqlite/src/db.ts';\nimport {getNormalizedZeroConfig} from '../config/zero-config.ts';\nimport {deleteLiteDB} from '../db/delete-lite-db.ts';\nimport {warmupConnections} from '../db/warmup.ts';\nimport {initEventSink, publishCriticalEvent} from '../observability/events.ts';\nimport {initializeCustomChangeSource} from '../services/change-source/custom/change-source.ts';\nimport {initializePostgresChangeSource} from '../services/change-source/pg/change-source.ts';\nimport {BackupMonitor} from '../services/change-streamer/backup-monitor.ts';\nimport {ChangeStreamerHttpServer} from '../services/change-streamer/change-streamer-http.ts';\nimport {initializeStreamer} from '../services/change-streamer/change-streamer-service.ts';\nimport type {ChangeStreamerService} from '../services/change-streamer/change-streamer.ts';\nimport {ReplicaMonitor} from '../services/change-streamer/replica-monitor.ts';\nimport {AutoResetSignal} from '../services/change-streamer/schema/tables.ts';\nimport {exitAfter, runUntilKilled} from '../services/life-cycle.ts';\nimport {replicationStatusError} from '../services/replicator/replication-status.ts';\nimport {pgClient} from '../types/pg.ts';\nimport {\n parentWorker,\n singleProcessMode,\n type Worker,\n} from '../types/processes.ts';\nimport {getShardConfig} from '../types/shards.ts';\nimport {createLogContext} from './logging.ts';\nimport {startOtelAuto} from './otel-start.ts';\n\nexport default async function runWorker(\n parent: Worker,\n env: NodeJS.ProcessEnv,\n ...args: string[]\n): Promise<void> {\n assert(args.length > 0, `parent startMs not specified`);\n const parentStartMs = parseInt(args[0]);\n\n const config = getNormalizedZeroConfig({env, argv: args.slice(1)});\n const {\n taskID,\n changeStreamer: {port, address, protocol, startupDelayMs},\n upstream,\n change,\n replica,\n initialSync,\n litestream,\n } = config;\n\n startOtelAuto(createLogContext(config, {worker: 'change-streamer'}, false));\n const lc = createLogContext(config, {worker: 'change-streamer'}, true);\n initEventSink(lc, config);\n\n // Kick off DB connection warmup in the background.\n const changeDB = pgClient(lc, change.db, {\n max: change.maxConns,\n connection: {['application_name']: 'zero-change-streamer'},\n });\n void warmupConnections(lc, changeDB, 'change');\n\n const {autoReset} = config;\n const shard = getShardConfig(config);\n\n let changeStreamer: ChangeStreamerService | undefined;\n\n for (const first of [true, false]) {\n try {\n // Note: This performs initial sync of the replica if necessary.\n const {changeSource, subscriptionState} =\n upstream.type === 'pg'\n ? await initializePostgresChangeSource(\n lc,\n upstream.db,\n shard,\n replica.file,\n initialSync,\n )\n : await initializeCustomChangeSource(\n lc,\n upstream.db,\n shard,\n replica.file,\n );\n\n changeStreamer = await initializeStreamer(\n lc,\n shard,\n taskID,\n address,\n protocol,\n changeDB,\n changeSource,\n subscriptionState,\n autoReset ?? false,\n );\n break;\n } catch (e) {\n if (first && e instanceof AutoResetSignal) {\n lc.warn?.(`resetting replica ${replica.file}`, e);\n // TODO: Make deleteLiteDB work with litestream. It will probably have to be\n // a semantic wipe instead of a file delete.\n deleteLiteDB(replica.file);\n continue; // execute again with a fresh initial-sync\n }\n await publishCriticalEvent(\n lc,\n replicationStatusError(lc, 'Initializing', e),\n );\n if (e instanceof DatabaseInitError) {\n throw new Error(\n `Cannot open ZERO_REPLICA_FILE at \"${replica.file}\". Please check that the path is valid.`,\n {cause: e},\n );\n }\n throw e;\n }\n }\n // impossible: upstream must have advanced in order for replication to be stuck.\n assert(changeStreamer, `resetting replica did not advance replicaVersion`);\n\n const {backupURL, port: metricsPort} = litestream;\n const monitor = backupURL\n ? new BackupMonitor(\n lc,\n backupURL,\n `http://localhost:${metricsPort}/metrics`,\n changeStreamer,\n // The time between when the zero-cache was started to when the\n // change-streamer is ready to start serves as the initial delay for\n // watermark cleanup (as it either includes a similar replica\n // restoration/preparation step, or an initial-sync, which\n // generally takes longer).\n //\n // Consider: Also account for permanent volumes?\n Date.now() - parentStartMs,\n )\n : new ReplicaMonitor(lc, replica.file, changeStreamer);\n\n const changeStreamerWebServer = new ChangeStreamerHttpServer(\n lc,\n config,\n {port, startupDelayMs},\n parent,\n changeStreamer,\n monitor instanceof BackupMonitor ? monitor : null,\n );\n\n parent.send(['ready', {ready: true}]);\n\n // Note: The changeStreamer itself is not started here; it is started by the\n // changeStreamerWebServer.\n return runUntilKilled(lc, parent, changeStreamerWebServer, monitor);\n}\n\n// fork()\nif (!singleProcessMode()) {\n void exitAfter(() =>\n runWorker(must(parentWorker), process.env, ...process.argv.slice(2)),\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;AA2BA,eAA8B,UAC5B,QACA,QACG,MACY;AACf,SAAO,KAAK,SAAS,GAAG,8BAA8B;AACtD,QAAM,gBAAgB,SAAS,KAAK,CAAC,CAAC;AAEtC,QAAM,SAAS,wBAAwB,EAAC,KAAK,MAAM,KAAK,MAAM,CAAC,GAAE;AACjE,QAAM;AAAA,IACJ;AAAA,IACA,gBAAgB,EAAC,MAAM,SAAS,UAAU,eAAA;AAAA,IAC1C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,IACE;AAEJ,gBAAc,iBAAiB,QAAQ,EAAC,QAAQ,kBAAA,GAAoB,KAAK,CAAC;AAC1E,QAAM,KAAK,iBAAiB,QAAQ,EAAC,QAAQ,kBAAA,GAAoB,IAAI;AACrE,gBAAc,IAAI,MAAM;AAGxB,QAAM,WAAW,SAAS,IAAI,OAAO,IAAI;AAAA,IACvC,KAAK,OAAO;AAAA,IACZ,YAAY,EAAC,CAAC,kBAAkB,GAAG,uBAAA;AAAA,EAAsB,CAC1D;AACD,OAAK,kBAAkB,IAAI,UAAU,QAAQ;AAE7C,QAAM,EAAC,cAAa;AACpB,QAAM,QAAQ,eAAe,MAAM;AAEnC,MAAI;AAEJ,aAAW,SAAS,CAAC,MAAM,KAAK,GAAG;AACjC,QAAI;AAEF,YAAM,EAAC,cAAc,kBAAA,IACnB,SAAS,SAAS,OACd,MAAM;AAAA,QACJ;AAAA,QACA,SAAS;AAAA,QACT;AAAA,QACA,QAAQ;AAAA,QACR;AAAA,MAAA,IAEF,MAAM;AAAA,QACJ;AAAA,QACA,SAAS;AAAA,QACT;AAAA,QACA,QAAQ;AAAA,MAAA;AAGhB,uBAAiB,MAAM;AAAA,QACrB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,aAAa;AAAA,MAAA;AAEf;AAAA,IACF,SAAS,GAAG;AACV,UAAI,SAAS,aAAa,iBAAiB;AACzC,WAAG,OAAO,qBAAqB,QAAQ,IAAI,IAAI,CAAC;AAGhD,qBAAa,QAAQ,IAAI;AACzB;AAAA,MACF;AACA,YAAM;AAAA,QACJ;AAAA,QACA,uBAAuB,IAAI,gBAAgB,CAAC;AAAA,MAAA;AAE9C,UAAI,aAAa,mBAAmB;AAClC,cAAM,IAAI;AAAA,UACR,qCAAqC,QAAQ,IAAI;AAAA,UACjD,EAAC,OAAO,EAAA;AAAA,QAAC;AAAA,MAEb;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAEA,SAAO,gBAAgB,kDAAkD;AAEzE,QAAM,EAAC,WAAW,MAAM,YAAA,IAAe;AACvC,QAAM,UAAU,YACZ,IAAI;AAAA,IACF;AAAA,IACA;AAAA,IACA,oBAAoB,WAAW;AAAA,IAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQA,KAAK,QAAQ;AAAA,EAAA,IAEf,IAAI,eAAe,IAAI,QAAQ,MAAM,cAAc;AAEvD,QAAM,0BAA0B,IAAI;AAAA,IAClC;AAAA,IACA;AAAA,IACA,EAAC,MAAM,eAAA;AAAA,IACP;AAAA,IACA;AAAA,IACA,mBAAmB,gBAAgB,UAAU;AAAA,EAAA;AAG/C,SAAO,KAAK,CAAC,SAAS,EAAC,OAAO,KAAA,CAAK,CAAC;AAIpC,SAAO,eAAe,IAAI,QAAQ,yBAAyB,OAAO;AACpE;AAGA,IAAI,CAAC,qBAAqB;AACxB,OAAK;AAAA,IAAU,MACb,UAAU,KAAK,YAAY,GAAG,QAAQ,KAAK,GAAG,QAAQ,KAAK,MAAM,CAAC,CAAC;AAAA,EAAA;AAEvE;"}
1
+ {"version":3,"file":"change-streamer.js","sources":["../../../../../zero-cache/src/server/change-streamer.ts"],"sourcesContent":["import {assert} from '../../../shared/src/asserts.ts';\nimport {must} from '../../../shared/src/must.ts';\nimport {DatabaseInitError} from '../../../zqlite/src/db.ts';\nimport {getNormalizedZeroConfig} from '../config/zero-config.ts';\nimport {deleteLiteDB} from '../db/delete-lite-db.ts';\nimport {warmupConnections} from '../db/warmup.ts';\nimport {initEventSink, publishCriticalEvent} from '../observability/events.ts';\nimport {initializeCustomChangeSource} from '../services/change-source/custom/change-source.ts';\nimport {initializePostgresChangeSource} from '../services/change-source/pg/change-source.ts';\nimport {BackupMonitor} from '../services/change-streamer/backup-monitor.ts';\nimport {ChangeStreamerHttpServer} from '../services/change-streamer/change-streamer-http.ts';\nimport {initializeStreamer} from '../services/change-streamer/change-streamer-service.ts';\nimport type {ChangeStreamerService} from '../services/change-streamer/change-streamer.ts';\nimport {ReplicaMonitor} from '../services/change-streamer/replica-monitor.ts';\nimport {AutoResetSignal} from '../services/change-streamer/schema/tables.ts';\nimport {exitAfter, runUntilKilled} from '../services/life-cycle.ts';\nimport {replicationStatusError} from '../services/replicator/replication-status.ts';\nimport {pgClient} from '../types/pg.ts';\nimport {\n parentWorker,\n singleProcessMode,\n type Worker,\n} from '../types/processes.ts';\nimport {getShardConfig} from '../types/shards.ts';\nimport {createLogContext} from './logging.ts';\nimport {startOtelAuto} from './otel-start.ts';\n\nexport default async function runWorker(\n parent: Worker,\n env: NodeJS.ProcessEnv,\n ...args: string[]\n): Promise<void> {\n assert(args.length > 0, `parent startMs not specified`);\n const parentStartMs = parseInt(args[0]);\n\n const config = getNormalizedZeroConfig({env, argv: args.slice(1)});\n const {\n taskID,\n changeStreamer: {port, address, protocol, startupDelayMs},\n upstream,\n change,\n replica,\n initialSync,\n litestream,\n } = config;\n\n startOtelAuto(createLogContext(config, {worker: 'change-streamer'}, false));\n const lc = createLogContext(config, {worker: 'change-streamer'}, true);\n initEventSink(lc, config);\n lc.info?.(\n `replication-manager litestream backupURL=${\n config.litestream.backupURL ?? '(none)'\n } replicaFile=${config.replica.file}`,\n );\n\n // Kick off DB connection warmup in the background.\n const changeDB = pgClient(lc, change.db, {\n max: change.maxConns,\n connection: {['application_name']: 'zero-change-streamer'},\n });\n void warmupConnections(lc, changeDB, 'change');\n\n const {autoReset} = config;\n const shard = getShardConfig(config);\n\n let changeStreamer: ChangeStreamerService | undefined;\n\n for (const first of [true, false]) {\n try {\n // Note: This performs initial sync of the replica if necessary.\n const {changeSource, subscriptionState} =\n upstream.type === 'pg'\n ? await initializePostgresChangeSource(\n lc,\n upstream.db,\n shard,\n replica.file,\n initialSync,\n )\n : await initializeCustomChangeSource(\n lc,\n upstream.db,\n shard,\n replica.file,\n );\n\n changeStreamer = await initializeStreamer(\n lc,\n shard,\n taskID,\n address,\n protocol,\n changeDB,\n changeSource,\n subscriptionState,\n autoReset ?? false,\n );\n break;\n } catch (e) {\n if (first && e instanceof AutoResetSignal) {\n lc.warn?.(`resetting replica ${replica.file}`, e);\n // TODO: Make deleteLiteDB work with litestream. It will probably have to be\n // a semantic wipe instead of a file delete.\n deleteLiteDB(replica.file);\n continue; // execute again with a fresh initial-sync\n }\n await publishCriticalEvent(\n lc,\n replicationStatusError(lc, 'Initializing', e),\n );\n if (e instanceof DatabaseInitError) {\n throw new Error(\n `Cannot open ZERO_REPLICA_FILE at \"${replica.file}\". Please check that the path is valid.`,\n {cause: e},\n );\n }\n throw e;\n }\n }\n // impossible: upstream must have advanced in order for replication to be stuck.\n assert(changeStreamer, `resetting replica did not advance replicaVersion`);\n\n const {backupURL, port: metricsPort} = litestream;\n const monitor = backupURL\n ? new BackupMonitor(\n lc,\n backupURL,\n `http://localhost:${metricsPort}/metrics`,\n changeStreamer,\n // The time between when the zero-cache was started to when the\n // change-streamer is ready to start serves as the initial delay for\n // watermark cleanup (as it either includes a similar replica\n // restoration/preparation step, or an initial-sync, which\n // generally takes longer).\n //\n // Consider: Also account for permanent volumes?\n Date.now() - parentStartMs,\n )\n : new ReplicaMonitor(lc, replica.file, changeStreamer);\n\n const changeStreamerWebServer = new ChangeStreamerHttpServer(\n lc,\n config,\n {port, startupDelayMs},\n parent,\n changeStreamer,\n monitor instanceof BackupMonitor ? monitor : null,\n );\n\n parent.send(['ready', {ready: true}]);\n\n // Note: The changeStreamer itself is not started here; it is started by the\n // changeStreamerWebServer.\n return runUntilKilled(lc, parent, changeStreamerWebServer, monitor);\n}\n\n// fork()\nif (!singleProcessMode()) {\n void exitAfter(() =>\n runWorker(must(parentWorker), process.env, ...process.argv.slice(2)),\n );\n}\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/server/main.ts"],"names":[],"mappings":"AAeA,OAAO,EAIL,KAAK,MAAM,EACZ,MAAM,uBAAuB,CAAC;AAoB/B,wBAA8B,SAAS,CACrC,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,CAAC,UAAU,GACrB,OAAO,CAAC,IAAI,CAAC,CA+Kf"}
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/server/main.ts"],"names":[],"mappings":"AAeA,OAAO,EAIL,KAAK,MAAM,EACZ,MAAM,uBAAuB,CAAC;AAoB/B,wBAA8B,SAAS,CACrC,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,CAAC,UAAU,GACrB,OAAO,CAAC,IAAI,CAAC,CAyLf"}
@@ -48,6 +48,9 @@ async function runWorker(parent, env) {
48
48
  const runChangeStreamer = changeStreamerMode === "dedicated" && changeStreamerURI === void 0;
49
49
  let restoreStart = /* @__PURE__ */ new Date();
50
50
  if (litestream.backupURL || litestream.executable && !runChangeStreamer) {
51
+ lc.info?.(
52
+ `dispatcher restore config role=${runChangeStreamer ? "replication-manager" : "view-syncer"} backupURL=${litestream.backupURL ?? "(none)"} replicaFile=${config.replica.file}`
53
+ );
51
54
  try {
52
55
  restoreStart = await restoreReplica(lc, config);
53
56
  } catch (e) {
@@ -73,6 +76,9 @@ async function runWorker(parent, env) {
73
76
  }
74
77
  await changeStreamerReady;
75
78
  if (runChangeStreamer && litestream.backupURL) {
79
+ lc.info?.(
80
+ `starting litestream replicate for replication-manager backupURL=${litestream.backupURL} replicaFile=${config.replica.file}`
81
+ );
76
82
  const { promise: backupReady, resolve } = resolver();
77
83
  const mode = "backup";
78
84
  loadWorker(REPLICATOR_URL, "supporting", mode, mode).once(
@@ -1 +1 @@
1
- {"version":3,"file":"main.js","sources":["../../../../../zero-cache/src/server/main.ts"],"sourcesContent":["import {resolver} from '@rocicorp/resolver';\nimport path from 'node:path';\nimport {must} from '../../../shared/src/must.ts';\nimport {getNormalizedZeroConfig} from '../config/zero-config.ts';\nimport {initEventSink} from '../observability/events.ts';\nimport {\n exitAfter,\n ProcessManager,\n runUntilKilled,\n type WorkerType,\n} from '../services/life-cycle.ts';\nimport {\n restoreReplica,\n startReplicaBackupProcess,\n} from '../services/litestream/commands.ts';\nimport {\n childWorker,\n parentWorker,\n singleProcessMode,\n type Worker,\n} from '../types/processes.ts';\nimport {\n createNotifierFrom,\n handleSubscriptionsFrom,\n type ReplicaFileMode,\n subscribeTo,\n} from '../workers/replicator.ts';\nimport {createLogContext} from './logging.ts';\nimport {startOtelAuto} from './otel-start.ts';\nimport {WorkerDispatcher} from './worker-dispatcher.ts';\nimport {\n CHANGE_STREAMER_URL,\n MUTATOR_URL,\n REAPER_URL,\n REPLICATOR_URL,\n SYNCER_URL,\n} from './worker-urls.ts';\n\nconst clientConnectionBifurcated = false;\n\nexport default async function runWorker(\n parent: Worker,\n env: NodeJS.ProcessEnv,\n): Promise<void> {\n const startMs = Date.now();\n const config = getNormalizedZeroConfig({env});\n\n startOtelAuto(createLogContext(config, {worker: 'dispatcher'}, false));\n const lc = createLogContext(config, {worker: 'dispatcher'}, true);\n initEventSink(lc, config);\n\n const processes = new ProcessManager(lc, parent);\n\n const {numSyncWorkers: numSyncers} = config;\n if (config.upstream.maxConns < numSyncers) {\n throw new Error(\n `Insufficient upstream connections (${config.upstream.maxConns}) for ${numSyncers} syncers.` +\n `Increase ZERO_UPSTREAM_MAX_CONNS or decrease ZERO_NUM_SYNC_WORKERS (which defaults to available cores).`,\n );\n }\n if (config.cvr.maxConns < numSyncers) {\n throw new Error(\n `Insufficient cvr connections (${config.cvr.maxConns}) for ${numSyncers} syncers.` +\n `Increase ZERO_CVR_MAX_CONNS or decrease ZERO_NUM_SYNC_WORKERS (which defaults to available cores).`,\n );\n }\n\n const internalFlags: string[] =\n numSyncers === 0\n ? []\n : [\n '--upstream-max-conns-per-worker',\n String(Math.floor(config.upstream.maxConns / numSyncers)),\n '--cvr-max-conns-per-worker',\n String(Math.floor(config.cvr.maxConns / numSyncers)),\n ];\n\n function loadWorker(\n moduleUrl: URL,\n type: WorkerType,\n id?: string | number,\n ...args: string[]\n ): Worker {\n const worker = childWorker(moduleUrl, env, ...args, ...internalFlags);\n const name = path.basename(moduleUrl.pathname) + (id ? ` (${id})` : '');\n return processes.addWorker(worker, type, name);\n }\n\n const {\n taskID,\n changeStreamer: {mode: changeStreamerMode, uri: changeStreamerURI},\n litestream,\n } = config;\n const runChangeStreamer =\n changeStreamerMode === 'dedicated' && changeStreamerURI === undefined;\n\n let restoreStart = new Date();\n if (litestream.backupURL || (litestream.executable && !runChangeStreamer)) {\n try {\n restoreStart = await restoreReplica(lc, config);\n } catch (e) {\n if (runChangeStreamer) {\n // If the restore failed, e.g. due to a corrupt backup, the\n // replication-manager recovers by re-syncing.\n lc.error?.('error restoring backup. resyncing the replica.', e);\n } else {\n // View-syncers, on the other hand, have no option other than to retry\n // until a valid backup has been published. This is achieved by\n // shutting down and letting the container runner retry with its\n // configured policy.\n throw e;\n }\n }\n }\n\n const {promise: changeStreamerReady, resolve: changeStreamerStarted} =\n resolver();\n const changeStreamer = runChangeStreamer\n ? loadWorker(\n CHANGE_STREAMER_URL,\n 'supporting',\n undefined,\n String(restoreStart.getTime()),\n ).once('message', changeStreamerStarted)\n : (changeStreamerStarted() ?? undefined);\n\n const {promise: reaperReady, resolve: reaperStarted} = resolver();\n if (numSyncers > 0) {\n loadWorker(REAPER_URL, 'supporting').once('message', reaperStarted);\n } else {\n reaperStarted();\n }\n\n // Wait for the change-streamer to be ready to guarantee that a replica\n // file is present.\n await changeStreamerReady;\n\n if (runChangeStreamer && litestream.backupURL) {\n // Start a backup replicator and corresponding litestream backup process.\n const {promise: backupReady, resolve} = resolver();\n const mode: ReplicaFileMode = 'backup';\n loadWorker(REPLICATOR_URL, 'supporting', mode, mode).once(\n // Wait for the Replicator's first message (i.e. \"ready\") before starting\n // litestream backup in order to avoid contending on the lock when the\n // replicator first prepares the db file.\n 'message',\n () => {\n processes.addSubprocess(\n startReplicaBackupProcess(config),\n 'supporting',\n 'litestream',\n );\n resolve();\n },\n );\n await backupReady;\n }\n\n // Before starting the view-syncers, ensure that the reaper has started\n // up, indicating that any CVR db migrations have been performed.\n await reaperReady;\n\n const syncers: Worker[] = [];\n if (numSyncers) {\n const mode: ReplicaFileMode =\n runChangeStreamer && litestream.backupURL ? 'serving-copy' : 'serving';\n const {promise: replicaReady, resolve} = resolver();\n const replicator = loadWorker(\n REPLICATOR_URL,\n 'supporting',\n mode,\n mode,\n ).once('message', () => {\n subscribeTo(lc, replicator);\n resolve();\n });\n await replicaReady;\n\n const notifier = createNotifierFrom(lc, replicator);\n for (let i = 0; i < numSyncers; i++) {\n syncers.push(loadWorker(SYNCER_URL, 'user-facing', i + 1, mode));\n }\n syncers.forEach(syncer => handleSubscriptionsFrom(lc, syncer, notifier));\n }\n let mutator: Worker | undefined;\n if (clientConnectionBifurcated) {\n mutator = loadWorker(MUTATOR_URL, 'supporting', 'mutator');\n }\n\n lc.info?.('waiting for workers to be ready ...');\n const logWaiting = setInterval(\n () => lc.info?.(`still waiting for ${processes.initializing().join(', ')}`),\n 10_000,\n );\n await processes.allWorkersReady();\n clearInterval(logWaiting);\n lc.info?.(`all workers ready (${Date.now() - startMs} ms)`);\n\n parent.send(['ready', {ready: true}]);\n\n try {\n await runUntilKilled(\n lc,\n parent,\n new WorkerDispatcher(\n lc,\n taskID,\n parent,\n syncers,\n mutator,\n changeStreamer,\n ),\n );\n } catch (err) {\n processes.logErrorAndExit(err, 'dispatcher');\n }\n\n await processes.done();\n}\n\nif (!singleProcessMode()) {\n void exitAfter(() => runWorker(must(parentWorker), process.env));\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"main.js","sources":["../../../../../zero-cache/src/server/main.ts"],"sourcesContent":["import {resolver} from '@rocicorp/resolver';\nimport path from 'node:path';\nimport {must} from '../../../shared/src/must.ts';\nimport {getNormalizedZeroConfig} from '../config/zero-config.ts';\nimport {initEventSink} from '../observability/events.ts';\nimport {\n exitAfter,\n ProcessManager,\n runUntilKilled,\n type WorkerType,\n} from '../services/life-cycle.ts';\nimport {\n restoreReplica,\n startReplicaBackupProcess,\n} from '../services/litestream/commands.ts';\nimport {\n childWorker,\n parentWorker,\n singleProcessMode,\n type Worker,\n} from '../types/processes.ts';\nimport {\n createNotifierFrom,\n handleSubscriptionsFrom,\n type ReplicaFileMode,\n subscribeTo,\n} from '../workers/replicator.ts';\nimport {createLogContext} from './logging.ts';\nimport {startOtelAuto} from './otel-start.ts';\nimport {WorkerDispatcher} from './worker-dispatcher.ts';\nimport {\n CHANGE_STREAMER_URL,\n MUTATOR_URL,\n REAPER_URL,\n REPLICATOR_URL,\n SYNCER_URL,\n} from './worker-urls.ts';\n\nconst clientConnectionBifurcated = false;\n\nexport default async function runWorker(\n parent: Worker,\n env: NodeJS.ProcessEnv,\n): Promise<void> {\n const startMs = Date.now();\n const config = getNormalizedZeroConfig({env});\n\n startOtelAuto(createLogContext(config, {worker: 'dispatcher'}, false));\n const lc = createLogContext(config, {worker: 'dispatcher'}, true);\n initEventSink(lc, config);\n\n const processes = new ProcessManager(lc, parent);\n\n const {numSyncWorkers: numSyncers} = config;\n if (config.upstream.maxConns < numSyncers) {\n throw new Error(\n `Insufficient upstream connections (${config.upstream.maxConns}) for ${numSyncers} syncers.` +\n `Increase ZERO_UPSTREAM_MAX_CONNS or decrease ZERO_NUM_SYNC_WORKERS (which defaults to available cores).`,\n );\n }\n if (config.cvr.maxConns < numSyncers) {\n throw new Error(\n `Insufficient cvr connections (${config.cvr.maxConns}) for ${numSyncers} syncers.` +\n `Increase ZERO_CVR_MAX_CONNS or decrease ZERO_NUM_SYNC_WORKERS (which defaults to available cores).`,\n );\n }\n\n const internalFlags: string[] =\n numSyncers === 0\n ? []\n : [\n '--upstream-max-conns-per-worker',\n String(Math.floor(config.upstream.maxConns / numSyncers)),\n '--cvr-max-conns-per-worker',\n String(Math.floor(config.cvr.maxConns / numSyncers)),\n ];\n\n function loadWorker(\n moduleUrl: URL,\n type: WorkerType,\n id?: string | number,\n ...args: string[]\n ): Worker {\n const worker = childWorker(moduleUrl, env, ...args, ...internalFlags);\n const name = path.basename(moduleUrl.pathname) + (id ? ` (${id})` : '');\n return processes.addWorker(worker, type, name);\n }\n\n const {\n taskID,\n changeStreamer: {mode: changeStreamerMode, uri: changeStreamerURI},\n litestream,\n } = config;\n const runChangeStreamer =\n changeStreamerMode === 'dedicated' && changeStreamerURI === undefined;\n\n let restoreStart = new Date();\n if (litestream.backupURL || (litestream.executable && !runChangeStreamer)) {\n lc.info?.(\n `dispatcher restore config role=${\n runChangeStreamer ? 'replication-manager' : 'view-syncer'\n } backupURL=${litestream.backupURL ?? '(none)'} replicaFile=${\n config.replica.file\n }`,\n );\n try {\n restoreStart = await restoreReplica(lc, config);\n } catch (e) {\n if (runChangeStreamer) {\n // If the restore failed, e.g. due to a corrupt backup, the\n // replication-manager recovers by re-syncing.\n lc.error?.('error restoring backup. resyncing the replica.', e);\n } else {\n // View-syncers, on the other hand, have no option other than to retry\n // until a valid backup has been published. This is achieved by\n // shutting down and letting the container runner retry with its\n // configured policy.\n throw e;\n }\n }\n }\n\n const {promise: changeStreamerReady, resolve: changeStreamerStarted} =\n resolver();\n const changeStreamer = runChangeStreamer\n ? loadWorker(\n CHANGE_STREAMER_URL,\n 'supporting',\n undefined,\n String(restoreStart.getTime()),\n ).once('message', changeStreamerStarted)\n : (changeStreamerStarted() ?? undefined);\n\n const {promise: reaperReady, resolve: reaperStarted} = resolver();\n if (numSyncers > 0) {\n loadWorker(REAPER_URL, 'supporting').once('message', reaperStarted);\n } else {\n reaperStarted();\n }\n\n // Wait for the change-streamer to be ready to guarantee that a replica\n // file is present.\n await changeStreamerReady;\n\n if (runChangeStreamer && litestream.backupURL) {\n lc.info?.(\n `starting litestream replicate for replication-manager backupURL=${litestream.backupURL} replicaFile=${config.replica.file}`,\n );\n // Start a backup replicator and corresponding litestream backup process.\n const {promise: backupReady, resolve} = resolver();\n const mode: ReplicaFileMode = 'backup';\n loadWorker(REPLICATOR_URL, 'supporting', mode, mode).once(\n // Wait for the Replicator's first message (i.e. \"ready\") before starting\n // litestream backup in order to avoid contending on the lock when the\n // replicator first prepares the db file.\n 'message',\n () => {\n processes.addSubprocess(\n startReplicaBackupProcess(config),\n 'supporting',\n 'litestream',\n );\n resolve();\n },\n );\n await backupReady;\n }\n\n // Before starting the view-syncers, ensure that the reaper has started\n // up, indicating that any CVR db migrations have been performed.\n await reaperReady;\n\n const syncers: Worker[] = [];\n if (numSyncers) {\n const mode: ReplicaFileMode =\n runChangeStreamer && litestream.backupURL ? 'serving-copy' : 'serving';\n const {promise: replicaReady, resolve} = resolver();\n const replicator = loadWorker(\n REPLICATOR_URL,\n 'supporting',\n mode,\n mode,\n ).once('message', () => {\n subscribeTo(lc, replicator);\n resolve();\n });\n await replicaReady;\n\n const notifier = createNotifierFrom(lc, replicator);\n for (let i = 0; i < numSyncers; i++) {\n syncers.push(loadWorker(SYNCER_URL, 'user-facing', i + 1, mode));\n }\n syncers.forEach(syncer => handleSubscriptionsFrom(lc, syncer, notifier));\n }\n let mutator: Worker | undefined;\n if (clientConnectionBifurcated) {\n mutator = loadWorker(MUTATOR_URL, 'supporting', 'mutator');\n }\n\n lc.info?.('waiting for workers to be ready ...');\n const logWaiting = setInterval(\n () => lc.info?.(`still waiting for ${processes.initializing().join(', ')}`),\n 10_000,\n );\n await processes.allWorkersReady();\n clearInterval(logWaiting);\n lc.info?.(`all workers ready (${Date.now() - startMs} ms)`);\n\n parent.send(['ready', {ready: true}]);\n\n try {\n await runUntilKilled(\n lc,\n parent,\n new WorkerDispatcher(\n lc,\n taskID,\n parent,\n syncers,\n mutator,\n changeStreamer,\n ),\n );\n } catch (err) {\n processes.logErrorAndExit(err, 'dispatcher');\n }\n\n await processes.done();\n}\n\nif (!singleProcessMode()) {\n void exitAfter(() => runWorker(must(parentWorker), process.env));\n}\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"run-worker.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/server/runner/run-worker.ts"],"names":[],"mappings":"AAAA,OAAO,kCAAkC,CAAC;AAO1C,OAAO,EAAc,KAAK,MAAM,EAAC,MAAM,0BAA0B,CAAC;AAMlE;;;;;;GAMG;AACH,wBAAsB,SAAS,CAC7B,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,GAAG,EAAE,MAAM,CAAC,UAAU,GACrB,OAAO,CAAC,IAAI,CAAC,CAuDf"}
1
+ {"version":3,"file":"run-worker.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/server/runner/run-worker.ts"],"names":[],"mappings":"AAAA,OAAO,kCAAkC,CAAC;AAO1C,OAAO,EAAc,KAAK,MAAM,EAAC,MAAM,0BAA0B,CAAC;AAMlE;;;;;;GAMG;AACH,wBAAsB,SAAS,CAC7B,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,GAAG,EAAE,MAAM,CAAC,UAAU,GACrB,OAAO,CAAC,IAAI,CAAC,CA0Df"}
@@ -17,9 +17,13 @@ async function runWorker(parent, env) {
17
17
  const processes = new ProcessManager(lc, parent ?? process);
18
18
  const { port, lazyStartup } = config;
19
19
  const serverVersion = getServerVersion(config);
20
- lc.info?.(
21
- `starting server${!serverVersion ? "" : `@${serverVersion}`} protocolVersion=${PROTOCOL_VERSION}`
22
- );
20
+ lc.info?.(`starting server${!serverVersion ? "" : `@${serverVersion}`} `, {
21
+ protocolVersion: PROTOCOL_VERSION,
22
+ taskID: config.taskID,
23
+ app: config.app,
24
+ shard: config.shard,
25
+ port: config.port
26
+ });
23
27
  let zeroCache;
24
28
  function startZeroCache() {
25
29
  if (zeroCache === void 0) {
@@ -1 +1 @@
1
- {"version":3,"file":"run-worker.js","sources":["../../../../../../zero-cache/src/server/runner/run-worker.ts"],"sourcesContent":["import '../../../../shared/src/dotenv.ts';\n\nimport {resolver, type Resolver} from '@rocicorp/resolver';\nimport {PROTOCOL_VERSION} from '../../../../zero-protocol/src/protocol-version.ts';\nimport {normalizeZeroConfig} from '../../config/normalize.ts';\nimport {getServerVersion, getZeroConfig} from '../../config/zero-config.ts';\nimport {ProcessManager, runUntilKilled} from '../../services/life-cycle.ts';\nimport {childWorker, type Worker} from '../../types/processes.ts';\nimport {createLogContext} from '../logging.ts';\nimport {MAIN_URL} from '../worker-urls.ts';\nimport {getTaskID} from './runtime.ts';\nimport {ZeroDispatcher} from './zero-dispatcher.ts';\n\n/**\n * Top-level `runner` entry point to the zero-cache. This layer is responsible for:\n * * runtime-based config normalization\n * * lazy startup\n * * serving /statsz\n * * auto-reset restarts (TODO)\n */\nexport async function runWorker(\n parent: Worker | null,\n env: NodeJS.ProcessEnv,\n): Promise<void> {\n // Note: Deprecation warnings are only emitted at this top-level parse;\n // they are suppressed when parsed in subprocesses.\n const cfg = getZeroConfig({env, emitDeprecationWarnings: true});\n const lc = createLogContext(cfg, {worker: 'runner'});\n\n const defaultTaskID = await getTaskID(lc);\n const config = normalizeZeroConfig(lc, cfg, env, defaultTaskID);\n const processes = new ProcessManager(lc, parent ?? process);\n\n const {port, lazyStartup} = config;\n const serverVersion = getServerVersion(config);\n lc.info?.(\n `starting server${!serverVersion ? '' : `@${serverVersion}`} ` +\n `protocolVersion=${PROTOCOL_VERSION}`,\n );\n\n let zeroCache: Resolver<Worker> | undefined;\n function startZeroCache(): Promise<Worker> {\n if (zeroCache === undefined) {\n const startMs = performance.now();\n lc.info?.('starting zero-cache');\n\n const r = (zeroCache = resolver<Worker>());\n const w = childWorker(MAIN_URL, env)\n .once('message', () => {\n r.resolve(w);\n lc.info?.(`zero-cache ready (${performance.now() - startMs} ms)`);\n })\n .once('error', r.reject);\n\n processes.addWorker(w, 'user-facing', 'zero-cache');\n }\n return zeroCache.promise;\n }\n\n // Eagerly start the zero-cache if it was not configured with --lazy-startup.\n if (!lazyStartup) {\n void startZeroCache();\n }\n\n await processes.allWorkersReady();\n parent?.send(['ready', {ready: true}]);\n\n try {\n await runUntilKilled(\n lc,\n parent ?? process,\n new ZeroDispatcher(config, lc, {port}, startZeroCache),\n );\n } catch (err) {\n processes.logErrorAndExit(err, 'main');\n }\n\n await processes.done();\n}\n"],"names":[],"mappings":";;;;;;;;;;;AAoBA,eAAsB,UACpB,QACA,KACe;AAGf,QAAM,MAAM,cAAc,EAAC,KAAK,yBAAyB,MAAK;AAC9D,QAAM,KAAK,iBAAiB,KAAK,EAAC,QAAQ,UAAS;AAEnD,QAAM,gBAAgB,MAAM,UAAU,EAAE;AACxC,QAAM,SAAS,oBAAoB,IAAI,KAAK,KAAK,aAAa;AAC9D,QAAM,YAAY,IAAI,eAAe,IAAI,UAAU,OAAO;AAE1D,QAAM,EAAC,MAAM,YAAA,IAAe;AAC5B,QAAM,gBAAgB,iBAAiB,MAAM;AAC7C,KAAG;AAAA,IACD,kBAAkB,CAAC,gBAAgB,KAAK,IAAI,aAAa,EAAE,oBACtC,gBAAgB;AAAA,EAAA;AAGvC,MAAI;AACJ,WAAS,iBAAkC;AACzC,QAAI,cAAc,QAAW;AAC3B,YAAM,UAAU,YAAY,IAAA;AAC5B,SAAG,OAAO,qBAAqB;AAE/B,YAAM,IAAK,YAAY,SAAA;AACvB,YAAM,IAAI,YAAY,UAAU,GAAG,EAChC,KAAK,WAAW,MAAM;AACrB,UAAE,QAAQ,CAAC;AACX,WAAG,OAAO,qBAAqB,YAAY,QAAQ,OAAO,MAAM;AAAA,MAClE,CAAC,EACA,KAAK,SAAS,EAAE,MAAM;AAEzB,gBAAU,UAAU,GAAG,eAAe,YAAY;AAAA,IACpD;AACA,WAAO,UAAU;AAAA,EACnB;AAGA,MAAI,CAAC,aAAa;AAChB,SAAK,eAAA;AAAA,EACP;AAEA,QAAM,UAAU,gBAAA;AAChB,UAAQ,KAAK,CAAC,SAAS,EAAC,OAAO,KAAA,CAAK,CAAC;AAErC,MAAI;AACF,UAAM;AAAA,MACJ;AAAA,MACA,UAAU;AAAA,MACV,IAAI,eAAe,QAAQ,IAAI,EAAC,KAAA,GAAO,cAAc;AAAA,IAAA;AAAA,EAEzD,SAAS,KAAK;AACZ,cAAU,gBAAgB,KAAK,MAAM;AAAA,EACvC;AAEA,QAAM,UAAU,KAAA;AAClB;"}
1
+ {"version":3,"file":"run-worker.js","sources":["../../../../../../zero-cache/src/server/runner/run-worker.ts"],"sourcesContent":["import '../../../../shared/src/dotenv.ts';\n\nimport {resolver, type Resolver} from '@rocicorp/resolver';\nimport {PROTOCOL_VERSION} from '../../../../zero-protocol/src/protocol-version.ts';\nimport {normalizeZeroConfig} from '../../config/normalize.ts';\nimport {getServerVersion, getZeroConfig} from '../../config/zero-config.ts';\nimport {ProcessManager, runUntilKilled} from '../../services/life-cycle.ts';\nimport {childWorker, type Worker} from '../../types/processes.ts';\nimport {createLogContext} from '../logging.ts';\nimport {MAIN_URL} from '../worker-urls.ts';\nimport {getTaskID} from './runtime.ts';\nimport {ZeroDispatcher} from './zero-dispatcher.ts';\n\n/**\n * Top-level `runner` entry point to the zero-cache. This layer is responsible for:\n * * runtime-based config normalization\n * * lazy startup\n * * serving /statsz\n * * auto-reset restarts (TODO)\n */\nexport async function runWorker(\n parent: Worker | null,\n env: NodeJS.ProcessEnv,\n): Promise<void> {\n // Note: Deprecation warnings are only emitted at this top-level parse;\n // they are suppressed when parsed in subprocesses.\n const cfg = getZeroConfig({env, emitDeprecationWarnings: true});\n const lc = createLogContext(cfg, {worker: 'runner'});\n\n const defaultTaskID = await getTaskID(lc);\n const config = normalizeZeroConfig(lc, cfg, env, defaultTaskID);\n const processes = new ProcessManager(lc, parent ?? process);\n\n const {port, lazyStartup} = config;\n const serverVersion = getServerVersion(config);\n lc.info?.(`starting server${!serverVersion ? '' : `@${serverVersion}`} `, {\n protocolVersion: PROTOCOL_VERSION,\n taskID: config.taskID,\n app: config.app,\n shard: config.shard,\n port: config.port,\n });\n\n let zeroCache: Resolver<Worker> | undefined;\n function startZeroCache(): Promise<Worker> {\n if (zeroCache === undefined) {\n const startMs = performance.now();\n lc.info?.('starting zero-cache');\n\n const r = (zeroCache = resolver<Worker>());\n const w = childWorker(MAIN_URL, env)\n .once('message', () => {\n r.resolve(w);\n lc.info?.(`zero-cache ready (${performance.now() - startMs} ms)`);\n })\n .once('error', r.reject);\n\n processes.addWorker(w, 'user-facing', 'zero-cache');\n }\n return zeroCache.promise;\n }\n\n // Eagerly start the zero-cache if it was not configured with --lazy-startup.\n if (!lazyStartup) {\n void startZeroCache();\n }\n\n await processes.allWorkersReady();\n parent?.send(['ready', {ready: true}]);\n\n try {\n await runUntilKilled(\n lc,\n parent ?? process,\n new ZeroDispatcher(config, lc, {port}, startZeroCache),\n );\n } catch (err) {\n processes.logErrorAndExit(err, 'main');\n }\n\n await processes.done();\n}\n"],"names":[],"mappings":";;;;;;;;;;;AAoBA,eAAsB,UACpB,QACA,KACe;AAGf,QAAM,MAAM,cAAc,EAAC,KAAK,yBAAyB,MAAK;AAC9D,QAAM,KAAK,iBAAiB,KAAK,EAAC,QAAQ,UAAS;AAEnD,QAAM,gBAAgB,MAAM,UAAU,EAAE;AACxC,QAAM,SAAS,oBAAoB,IAAI,KAAK,KAAK,aAAa;AAC9D,QAAM,YAAY,IAAI,eAAe,IAAI,UAAU,OAAO;AAE1D,QAAM,EAAC,MAAM,YAAA,IAAe;AAC5B,QAAM,gBAAgB,iBAAiB,MAAM;AAC7C,KAAG,OAAO,kBAAkB,CAAC,gBAAgB,KAAK,IAAI,aAAa,EAAE,KAAK;AAAA,IACxE,iBAAiB;AAAA,IACjB,QAAQ,OAAO;AAAA,IACf,KAAK,OAAO;AAAA,IACZ,OAAO,OAAO;AAAA,IACd,MAAM,OAAO;AAAA,EAAA,CACd;AAED,MAAI;AACJ,WAAS,iBAAkC;AACzC,QAAI,cAAc,QAAW;AAC3B,YAAM,UAAU,YAAY,IAAA;AAC5B,SAAG,OAAO,qBAAqB;AAE/B,YAAM,IAAK,YAAY,SAAA;AACvB,YAAM,IAAI,YAAY,UAAU,GAAG,EAChC,KAAK,WAAW,MAAM;AACrB,UAAE,QAAQ,CAAC;AACX,WAAG,OAAO,qBAAqB,YAAY,QAAQ,OAAO,MAAM;AAAA,MAClE,CAAC,EACA,KAAK,SAAS,EAAE,MAAM;AAEzB,gBAAU,UAAU,GAAG,eAAe,YAAY;AAAA,IACpD;AACA,WAAO,UAAU;AAAA,EACnB;AAGA,MAAI,CAAC,aAAa;AAChB,SAAK,eAAA;AAAA,EACP;AAEA,QAAM,UAAU,gBAAA;AAChB,UAAQ,KAAK,CAAC,SAAS,EAAC,OAAO,KAAA,CAAK,CAAC;AAErC,MAAI;AACF,UAAM;AAAA,MACJ;AAAA,MACA,UAAU;AAAA,MACV,IAAI,eAAe,QAAQ,IAAI,EAAC,KAAA,GAAO,cAAc;AAAA,IAAA;AAAA,EAEzD,SAAS,KAAK;AACZ,cAAU,gBAAgB,KAAK,MAAM;AAAA,EACvC;AAEA,QAAM,UAAU,KAAA;AAClB;"}
@@ -1 +1 @@
1
- {"version":3,"file":"syncer.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/server/syncer.ts"],"names":[],"mappings":"AAuBA,OAAO,EAGL,KAAK,MAAM,EACZ,MAAM,uBAAuB,CAAC;AA8B/B,MAAM,CAAC,OAAO,UAAU,SAAS,CAC/B,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,CAAC,UAAU,EACtB,GAAG,IAAI,EAAE,MAAM,EAAE,GAChB,OAAO,CAAC,IAAI,CAAC,CAsJf"}
1
+ {"version":3,"file":"syncer.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/server/syncer.ts"],"names":[],"mappings":"AAuBA,OAAO,EAGL,KAAK,MAAM,EACZ,MAAM,uBAAuB,CAAC;AA8B/B,MAAM,CAAC,OAAO,UAAU,SAAS,CAC/B,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,CAAC,UAAU,EACtB,GAAG,IAAI,EAAE,MAAM,EAAE,GAChB,OAAO,CAAC,IAAI,CAAC,CA2Jf"}
@@ -45,6 +45,9 @@ function runWorker(parent, env, ...args) {
45
45
  startOtelAuto(createLogContext(config, { worker: "syncer" }, false));
46
46
  const lc = createLogContext(config, { worker: "syncer" }, true);
47
47
  initEventSink(lc, config);
48
+ lc.info?.(
49
+ `view-syncer litestream backupURL=${config.litestream.backupURL ?? "(none)"} replicaFile=${config.replica.file}`
50
+ );
48
51
  assert(args.length > 0, `replicator mode not specified`);
49
52
  const fileMode = parse(args[0], replicaFileModeSchema);
50
53
  const { cvr, upstream } = config;
@@ -1 +1 @@
1
- {"version":3,"file":"syncer.js","sources":["../../../../../zero-cache/src/server/syncer.ts"],"sourcesContent":["import {randomUUID} from 'node:crypto';\nimport {tmpdir} from 'node:os';\nimport path from 'node:path';\nimport {pid} from 'node:process';\nimport {assert} from '../../../shared/src/asserts.ts';\nimport {must} from '../../../shared/src/must.ts';\nimport {randInt} from '../../../shared/src/rand.ts';\nimport * as v from '../../../shared/src/valita.ts';\nimport {DatabaseStorage} from '../../../zqlite/src/database-storage.ts';\nimport type {NormalizedZeroConfig} from '../config/normalize.ts';\nimport {getNormalizedZeroConfig} from '../config/zero-config.ts';\nimport {CustomQueryTransformer} from '../custom-queries/transform-query.ts';\nimport {warmupConnections} from '../db/warmup.ts';\nimport {initEventSink} from '../observability/events.ts';\nimport {exitAfter, runUntilKilled} from '../services/life-cycle.ts';\nimport {MutagenService} from '../services/mutagen/mutagen.ts';\nimport {PusherService} from '../services/mutagen/pusher.ts';\nimport type {ReplicaState} from '../services/replicator/replicator.ts';\nimport type {DrainCoordinator} from '../services/view-syncer/drain-coordinator.ts';\nimport {PipelineDriver} from '../services/view-syncer/pipeline-driver.ts';\nimport {Snapshotter} from '../services/view-syncer/snapshotter.ts';\nimport {ViewSyncerService} from '../services/view-syncer/view-syncer.ts';\nimport {pgClient} from '../types/pg.ts';\nimport {\n parentWorker,\n singleProcessMode,\n type Worker,\n} from '../types/processes.ts';\nimport {getShardID} from '../types/shards.ts';\nimport type {Subscription} from '../types/subscription.ts';\nimport {replicaFileModeSchema, replicaFileName} from '../workers/replicator.ts';\nimport {Syncer} from '../workers/syncer.ts';\nimport {startAnonymousTelemetry} from './anonymous-otel-start.ts';\nimport {InspectorDelegate} from './inspector-delegate.ts';\nimport {createLogContext} from './logging.ts';\nimport {startOtelAuto} from './otel-start.ts';\nimport {isPriorityOpRunning, runPriorityOp} from './priority-op.ts';\n\nfunction randomID() {\n return randInt(1, Number.MAX_SAFE_INTEGER).toString(36);\n}\n\nfunction getCustomQueryConfig(\n config: Pick<NormalizedZeroConfig, 'query' | 'getQueries'>,\n) {\n const queryConfig = config.query?.url ? config.query : config.getQueries;\n\n if (!queryConfig?.url) {\n return undefined;\n }\n\n return {\n url: queryConfig.url,\n forwardCookies: queryConfig.forwardCookies ?? false,\n };\n}\n\nexport default function runWorker(\n parent: Worker,\n env: NodeJS.ProcessEnv,\n ...args: string[]\n): Promise<void> {\n const config = getNormalizedZeroConfig({env, argv: args.slice(1)});\n\n startOtelAuto(createLogContext(config, {worker: 'syncer'}, false));\n const lc = createLogContext(config, {worker: 'syncer'}, true);\n initEventSink(lc, config);\n\n assert(args.length > 0, `replicator mode not specified`);\n const fileMode = v.parse(args[0], replicaFileModeSchema);\n\n const {cvr, upstream} = config;\n assert(cvr.maxConnsPerWorker, 'cvr.maxConnsPerWorker must be set');\n assert(upstream.maxConnsPerWorker, 'upstream.maxConnsPerWorker must be set');\n\n const replicaFile = replicaFileName(config.replica.file, fileMode);\n lc.debug?.(`running view-syncer on ${replicaFile}`);\n\n const cvrDB = pgClient(lc, cvr.db, {\n max: cvr.maxConnsPerWorker,\n connection: {['application_name']: `zero-sync-worker-${pid}-cvr`},\n });\n\n const upstreamDB = pgClient(lc, upstream.db, {\n max: upstream.maxConnsPerWorker,\n connection: {['application_name']: `zero-sync-worker-${pid}-upstream`},\n });\n\n const dbWarmup = Promise.allSettled([\n warmupConnections(lc, cvrDB, 'cvr'),\n warmupConnections(lc, upstreamDB, 'upstream'),\n ]);\n\n const tmpDir = config.storageDBTmpDir ?? tmpdir();\n const operatorStorage = DatabaseStorage.create(\n lc,\n path.join(tmpDir, `sync-worker-${randomUUID()}`),\n );\n const writeAuthzStorage = DatabaseStorage.create(\n lc,\n path.join(tmpDir, `mutagen-${randomUUID()}`),\n );\n\n const shard = getShardID(config);\n\n const viewSyncerFactory = (\n id: string,\n sub: Subscription<ReplicaState>,\n drainCoordinator: DrainCoordinator,\n ) => {\n const logger = lc\n .withContext('component', 'view-syncer')\n .withContext('clientGroupID', id)\n .withContext('instance', randomID());\n lc.debug?.(\n `creating view syncer. Query Planner Enabled: ${config.enableQueryPlanner}`,\n );\n\n // Create the custom query transformer if configured\n const customQueryConfig = getCustomQueryConfig(config);\n const customQueryTransformer =\n customQueryConfig &&\n new CustomQueryTransformer(logger, customQueryConfig, shard);\n\n const inspectorDelegate = new InspectorDelegate(customQueryTransformer);\n\n const priorityOpRunningYieldThresholdMs = Math.max(\n config.yieldThresholdMs / 4,\n 2,\n );\n const normalYieldThresholdMs = Math.max(config.yieldThresholdMs, 2);\n return new ViewSyncerService(\n config,\n logger,\n shard,\n config.taskID,\n id,\n cvrDB,\n config.upstream.type === 'pg' ? upstreamDB : undefined,\n new PipelineDriver(\n logger,\n config.log,\n new Snapshotter(\n logger,\n replicaFile,\n shard,\n config.replica.pageCacheSizeKib,\n ),\n shard,\n operatorStorage.createClientGroupStorage(id),\n id,\n inspectorDelegate,\n () =>\n isPriorityOpRunning()\n ? priorityOpRunningYieldThresholdMs\n : normalYieldThresholdMs,\n config.enableQueryPlanner,\n config,\n ),\n sub,\n drainCoordinator,\n config.log.slowHydrateThreshold,\n inspectorDelegate,\n customQueryTransformer,\n runPriorityOp,\n );\n };\n\n const mutagenFactory = (id: string) =>\n new MutagenService(\n lc.withContext('component', 'mutagen').withContext('clientGroupID', id),\n shard,\n id,\n upstreamDB,\n config,\n writeAuthzStorage,\n );\n\n const pusherFactory =\n config.push.url === undefined && config.mutate.url === undefined\n ? undefined\n : (id: string) =>\n new PusherService(\n upstreamDB,\n config,\n {\n ...config.push,\n ...config.mutate,\n url: must(\n config.push.url ?? config.mutate.url,\n 'No push or mutate URL configured',\n ),\n },\n lc.withContext('clientGroupID', id),\n id,\n );\n\n const syncer = new Syncer(\n lc,\n config,\n viewSyncerFactory,\n mutagenFactory,\n pusherFactory,\n parent,\n );\n\n startAnonymousTelemetry(lc, config);\n\n void dbWarmup.then(() => parent.send(['ready', {ready: true}]));\n\n return runUntilKilled(lc, parent, syncer);\n}\n\n// fork()\nif (!singleProcessMode()) {\n void exitAfter(() =>\n runWorker(must(parentWorker), process.env, ...process.argv.slice(2)),\n );\n}\n"],"names":["v.parse"],"mappings":"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"}
1
+ {"version":3,"file":"syncer.js","sources":["../../../../../zero-cache/src/server/syncer.ts"],"sourcesContent":["import {randomUUID} from 'node:crypto';\nimport {tmpdir} from 'node:os';\nimport path from 'node:path';\nimport {pid} from 'node:process';\nimport {assert} from '../../../shared/src/asserts.ts';\nimport {must} from '../../../shared/src/must.ts';\nimport {randInt} from '../../../shared/src/rand.ts';\nimport * as v from '../../../shared/src/valita.ts';\nimport {DatabaseStorage} from '../../../zqlite/src/database-storage.ts';\nimport type {NormalizedZeroConfig} from '../config/normalize.ts';\nimport {getNormalizedZeroConfig} from '../config/zero-config.ts';\nimport {CustomQueryTransformer} from '../custom-queries/transform-query.ts';\nimport {warmupConnections} from '../db/warmup.ts';\nimport {initEventSink} from '../observability/events.ts';\nimport {exitAfter, runUntilKilled} from '../services/life-cycle.ts';\nimport {MutagenService} from '../services/mutagen/mutagen.ts';\nimport {PusherService} from '../services/mutagen/pusher.ts';\nimport type {ReplicaState} from '../services/replicator/replicator.ts';\nimport type {DrainCoordinator} from '../services/view-syncer/drain-coordinator.ts';\nimport {PipelineDriver} from '../services/view-syncer/pipeline-driver.ts';\nimport {Snapshotter} from '../services/view-syncer/snapshotter.ts';\nimport {ViewSyncerService} from '../services/view-syncer/view-syncer.ts';\nimport {pgClient} from '../types/pg.ts';\nimport {\n parentWorker,\n singleProcessMode,\n type Worker,\n} from '../types/processes.ts';\nimport {getShardID} from '../types/shards.ts';\nimport type {Subscription} from '../types/subscription.ts';\nimport {replicaFileModeSchema, replicaFileName} from '../workers/replicator.ts';\nimport {Syncer} from '../workers/syncer.ts';\nimport {startAnonymousTelemetry} from './anonymous-otel-start.ts';\nimport {InspectorDelegate} from './inspector-delegate.ts';\nimport {createLogContext} from './logging.ts';\nimport {startOtelAuto} from './otel-start.ts';\nimport {isPriorityOpRunning, runPriorityOp} from './priority-op.ts';\n\nfunction randomID() {\n return randInt(1, Number.MAX_SAFE_INTEGER).toString(36);\n}\n\nfunction getCustomQueryConfig(\n config: Pick<NormalizedZeroConfig, 'query' | 'getQueries'>,\n) {\n const queryConfig = config.query?.url ? config.query : config.getQueries;\n\n if (!queryConfig?.url) {\n return undefined;\n }\n\n return {\n url: queryConfig.url,\n forwardCookies: queryConfig.forwardCookies ?? false,\n };\n}\n\nexport default function runWorker(\n parent: Worker,\n env: NodeJS.ProcessEnv,\n ...args: string[]\n): Promise<void> {\n const config = getNormalizedZeroConfig({env, argv: args.slice(1)});\n\n startOtelAuto(createLogContext(config, {worker: 'syncer'}, false));\n const lc = createLogContext(config, {worker: 'syncer'}, true);\n initEventSink(lc, config);\n lc.info?.(\n `view-syncer litestream backupURL=${\n config.litestream.backupURL ?? '(none)'\n } replicaFile=${config.replica.file}`,\n );\n\n assert(args.length > 0, `replicator mode not specified`);\n const fileMode = v.parse(args[0], replicaFileModeSchema);\n\n const {cvr, upstream} = config;\n assert(cvr.maxConnsPerWorker, 'cvr.maxConnsPerWorker must be set');\n assert(upstream.maxConnsPerWorker, 'upstream.maxConnsPerWorker must be set');\n\n const replicaFile = replicaFileName(config.replica.file, fileMode);\n lc.debug?.(`running view-syncer on ${replicaFile}`);\n\n const cvrDB = pgClient(lc, cvr.db, {\n max: cvr.maxConnsPerWorker,\n connection: {['application_name']: `zero-sync-worker-${pid}-cvr`},\n });\n\n const upstreamDB = pgClient(lc, upstream.db, {\n max: upstream.maxConnsPerWorker,\n connection: {['application_name']: `zero-sync-worker-${pid}-upstream`},\n });\n\n const dbWarmup = Promise.allSettled([\n warmupConnections(lc, cvrDB, 'cvr'),\n warmupConnections(lc, upstreamDB, 'upstream'),\n ]);\n\n const tmpDir = config.storageDBTmpDir ?? tmpdir();\n const operatorStorage = DatabaseStorage.create(\n lc,\n path.join(tmpDir, `sync-worker-${randomUUID()}`),\n );\n const writeAuthzStorage = DatabaseStorage.create(\n lc,\n path.join(tmpDir, `mutagen-${randomUUID()}`),\n );\n\n const shard = getShardID(config);\n\n const viewSyncerFactory = (\n id: string,\n sub: Subscription<ReplicaState>,\n drainCoordinator: DrainCoordinator,\n ) => {\n const logger = lc\n .withContext('component', 'view-syncer')\n .withContext('clientGroupID', id)\n .withContext('instance', randomID());\n lc.debug?.(\n `creating view syncer. Query Planner Enabled: ${config.enableQueryPlanner}`,\n );\n\n // Create the custom query transformer if configured\n const customQueryConfig = getCustomQueryConfig(config);\n const customQueryTransformer =\n customQueryConfig &&\n new CustomQueryTransformer(logger, customQueryConfig, shard);\n\n const inspectorDelegate = new InspectorDelegate(customQueryTransformer);\n\n const priorityOpRunningYieldThresholdMs = Math.max(\n config.yieldThresholdMs / 4,\n 2,\n );\n const normalYieldThresholdMs = Math.max(config.yieldThresholdMs, 2);\n return new ViewSyncerService(\n config,\n logger,\n shard,\n config.taskID,\n id,\n cvrDB,\n config.upstream.type === 'pg' ? upstreamDB : undefined,\n new PipelineDriver(\n logger,\n config.log,\n new Snapshotter(\n logger,\n replicaFile,\n shard,\n config.replica.pageCacheSizeKib,\n ),\n shard,\n operatorStorage.createClientGroupStorage(id),\n id,\n inspectorDelegate,\n () =>\n isPriorityOpRunning()\n ? priorityOpRunningYieldThresholdMs\n : normalYieldThresholdMs,\n config.enableQueryPlanner,\n config,\n ),\n sub,\n drainCoordinator,\n config.log.slowHydrateThreshold,\n inspectorDelegate,\n customQueryTransformer,\n runPriorityOp,\n );\n };\n\n const mutagenFactory = (id: string) =>\n new MutagenService(\n lc.withContext('component', 'mutagen').withContext('clientGroupID', id),\n shard,\n id,\n upstreamDB,\n config,\n writeAuthzStorage,\n );\n\n const pusherFactory =\n config.push.url === undefined && config.mutate.url === undefined\n ? undefined\n : (id: string) =>\n new PusherService(\n upstreamDB,\n config,\n {\n ...config.push,\n ...config.mutate,\n url: must(\n config.push.url ?? config.mutate.url,\n 'No push or mutate URL configured',\n ),\n },\n lc.withContext('clientGroupID', id),\n id,\n );\n\n const syncer = new Syncer(\n lc,\n config,\n viewSyncerFactory,\n mutagenFactory,\n pusherFactory,\n parent,\n );\n\n startAnonymousTelemetry(lc, config);\n\n void dbWarmup.then(() => parent.send(['ready', {ready: true}]));\n\n return runUntilKilled(lc, parent, syncer);\n}\n\n// fork()\nif (!singleProcessMode()) {\n void exitAfter(() =>\n runWorker(must(parentWorker), process.env, ...process.argv.slice(2)),\n );\n}\n"],"names":["v.parse"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"change-source.d.ts","sourceRoot":"","sources":["../../../../../../../zero-cache/src/services/change-source/pg/change-source.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAgBjD,OAAO,KAAK,EAEV,kBAAkB,EAEnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAIL,KAAK,WAAW,EACjB,MAAM,gCAAgC,CAAC;AAExC,OAAO,EAEL,KAAK,WAAW,EAEjB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,2BAA2B,CAAC;AAEpD,OAAO,KAAK,EACV,YAAY,EAEb,MAAM,kDAAkD,CAAC;AAE1D,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,8CAA8C,CAAC;AAYtD,OAAO,EAAC,KAAK,kBAAkB,EAAC,MAAM,mBAAmB,CAAC;AAC1D,OAAO,KAAK,EAGV,eAAe,IAAI,gBAAgB,EACpC,MAAM,yCAAyC,CAAC;AAoBjD;;;;GAIG;AACH,wBAAsB,8BAA8B,CAClD,EAAE,EAAE,UAAU,EACd,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,WAAW,EAClB,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,kBAAkB,GAC9B,OAAO,CAAC;IAAC,iBAAiB,EAAE,iBAAiB,CAAC;IAAC,YAAY,EAAE,YAAY,CAAA;CAAC,CAAC,CAoC7E;AA6PD,qBAAa,KAAK;;gBAIJ,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC;IAI9B,SAAS;IAiBT,GAAG,CAAC,SAAS,EAAE,WAAW;CAa3B;AAycD,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,kBAAkB,EAAE,CAAC,EAAE,gBAAgB,WAwB3E"}
1
+ {"version":3,"file":"change-source.d.ts","sourceRoot":"","sources":["../../../../../../../zero-cache/src/services/change-source/pg/change-source.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAgBjD,OAAO,KAAK,EAEV,kBAAkB,EAEnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAIL,KAAK,WAAW,EACjB,MAAM,gCAAgC,CAAC;AAExC,OAAO,EAEL,KAAK,WAAW,EAEjB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,2BAA2B,CAAC;AAEpD,OAAO,KAAK,EACV,YAAY,EAEb,MAAM,kDAAkD,CAAC;AAE1D,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,8CAA8C,CAAC;AAYtD,OAAO,EAAC,KAAK,kBAAkB,EAAC,MAAM,mBAAmB,CAAC;AAC1D,OAAO,KAAK,EAGV,eAAe,IAAI,gBAAgB,EACpC,MAAM,yCAAyC,CAAC;AAoBjD;;;;GAIG;AACH,wBAAsB,8BAA8B,CAClD,EAAE,EAAE,UAAU,EACd,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,WAAW,EAClB,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,kBAAkB,GAC9B,OAAO,CAAC;IAAC,iBAAiB,EAAE,iBAAiB,CAAC;IAAC,YAAY,EAAE,YAAY,CAAA;CAAC,CAAC,CAoC7E;AAsUD,qBAAa,KAAK;;gBAIJ,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC;IAI9B,SAAS;IAiBT,GAAG,CAAC,SAAS,EAAE,WAAW;CAa3B;AAycD,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,kBAAkB,EAAE,CAAC,EAAE,gBAAgB,WAwB3E"}
@@ -71,6 +71,16 @@ async function checkAndUpdateUpstream(lc, sql, shard, { replicaVersion, publicat
71
71
  replicaVersion
72
72
  );
73
73
  if (!upstreamReplica) {
74
+ const replicasTable = `${upstreamSchema(shard)}.replicas`;
75
+ const configuredReplicas = await sql`
76
+ SELECT slot, version
77
+ FROM ${sql(replicasTable)}
78
+ ORDER BY version, slot`;
79
+ lc.warn?.(
80
+ `No replication slot metadata match for replicaVersion=${replicaVersion} in ${replicasTable}. Available records: ${JSON.stringify(
81
+ configuredReplicas
82
+ )}`
83
+ );
74
84
  throw new AutoResetSignal(
75
85
  `No replication slot for replica at version ${replicaVersion}`
76
86
  );
@@ -196,18 +206,56 @@ class PostgresChangeSource {
196
206
  async #stopExistingReplicationSlotSubscribers(sql, slotToKeep) {
197
207
  const slotExpression = replicationSlotExpression(this.#shard);
198
208
  const legacySlotName = legacyReplicationSlot(this.#shard);
209
+ const replicasTable = `${upstreamSchema(this.#shard)}.replicas`;
210
+ this.#lc.info?.(
211
+ `cleaning up replication subscribers slotToKeep=${slotToKeep}, slotExpression=${slotExpression}, legacySlot=${legacySlotName}`
212
+ );
199
213
  const result = await sql`
200
- SELECT slot_name as slot, pg_terminate_backend(active_pid), active_pid as pid
214
+ SELECT slot_name as slot, pg_terminate_backend(active_pid) as terminated, active_pid as pid
201
215
  FROM pg_replication_slots
202
216
  WHERE (slot_name LIKE ${slotExpression} OR slot_name = ${legacySlotName})
203
217
  AND slot_name <= ${slotToKeep}`;
218
+ this.#lc.info?.(
219
+ `replication slots targeted for termination: ${JSON.stringify(result)}`
220
+ );
204
221
  if (result.length === 0) {
222
+ const shardSlots = await sql`
223
+ SELECT slot_name as slot, active, active_pid as pid
224
+ FROM pg_replication_slots
225
+ WHERE slot_name LIKE ${slotExpression} OR slot_name = ${legacySlotName}
226
+ ORDER BY slot_name`;
227
+ this.#lc.warn?.(
228
+ `slot ${slotToKeep} not found while cleaning subscribers; shard slots at time of failure: ${JSON.stringify(
229
+ shardSlots
230
+ )}`
231
+ );
205
232
  throw new AbortError(
206
233
  `replication slot ${slotToKeep} is missing. A different replication-manager should now be running on a new replication slot.`
207
234
  );
208
235
  }
209
- const replicasTable = `${upstreamSchema(this.#shard)}.replicas`;
210
- await sql`DELETE FROM ${sql(replicasTable)} WHERE slot != ${slotToKeep}`;
236
+ const replicasBefore = await sql`
237
+ SELECT slot, version FROM ${sql(replicasTable)} ORDER BY slot`;
238
+ this.#lc.info?.(
239
+ `replicas before cleanup (slotToKeep=${slotToKeep}): ${JSON.stringify(
240
+ replicasBefore
241
+ )}`
242
+ );
243
+ const deletedReplicas = await sql`
244
+ DELETE FROM ${sql(replicasTable)}
245
+ WHERE slot != ${slotToKeep}
246
+ RETURNING slot, version`;
247
+ this.#lc.warn?.(
248
+ `deleted replica metadata rows while keeping ${slotToKeep}: ${JSON.stringify(
249
+ deletedReplicas
250
+ )}`
251
+ );
252
+ const replicasAfter = await sql`
253
+ SELECT slot, version FROM ${sql(replicasTable)} ORDER BY slot`;
254
+ this.#lc.info?.(
255
+ `replicas after cleanup (slotToKeep=${slotToKeep}): ${JSON.stringify(
256
+ replicasAfter
257
+ )}`
258
+ );
211
259
  const pids = result.filter(({ pid }) => pid !== null).map(({ pid }) => pid);
212
260
  if (pids.length) {
213
261
  this.#lc.info?.(`signaled subscriber ${pids} to shut down`);
@@ -219,13 +267,30 @@ class PostgresChangeSource {
219
267
  }
220
268
  async #dropReplicationSlots(sql, slots) {
221
269
  this.#lc.info?.(`dropping other replication slot(s) ${slots}`);
270
+ const existingBefore = await sql`
271
+ SELECT slot_name as slot, active
272
+ FROM pg_replication_slots
273
+ WHERE slot_name IN ${sql(slots)}
274
+ ORDER BY slot_name`;
275
+ this.#lc.info?.(
276
+ `replication slots before drop attempt: ${JSON.stringify(existingBefore)}`
277
+ );
222
278
  for (let i = 0; i < 5; i++) {
223
279
  try {
224
280
  await sql`
225
281
  SELECT pg_drop_replication_slot(slot_name) FROM pg_replication_slots
226
282
  WHERE slot_name IN ${sql(slots)}
227
283
  `;
228
- this.#lc.info?.(`successfully dropped ${slots}`);
284
+ const remaining = await sql`
285
+ SELECT slot_name as slot
286
+ FROM pg_replication_slots
287
+ WHERE slot_name IN ${sql(slots)}
288
+ ORDER BY slot_name`;
289
+ this.#lc.info?.(
290
+ `successfully dropped ${slots}; remaining after drop: ${JSON.stringify(
291
+ remaining
292
+ )}`
293
+ );
229
294
  return;
230
295
  } catch (e) {
231
296
  if (e instanceof postgres.PostgresError && e.code === PG_OBJECT_IN_USE) {