@rocicorp/zero 1.0.0 → 1.0.1-canary.0
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.
- package/out/analyze-query/src/bin-analyze.js +19 -7
- package/out/analyze-query/src/bin-analyze.js.map +1 -1
- package/out/zero/package.js +1 -1
- package/out/zero/package.js.map +1 -1
- package/out/zero-cache/src/config/zero-config.d.ts +6 -0
- package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
- package/out/zero-cache/src/config/zero-config.js +12 -0
- package/out/zero-cache/src/config/zero-config.js.map +1 -1
- package/out/zero-cache/src/server/anonymous-otel-start.d.ts.map +1 -1
- package/out/zero-cache/src/server/anonymous-otel-start.js +1 -14
- package/out/zero-cache/src/server/anonymous-otel-start.js.map +1 -1
- package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
- package/out/zero-cache/src/server/change-streamer.js +2 -2
- package/out/zero-cache/src/server/change-streamer.js.map +1 -1
- package/out/zero-cache/src/services/analyze.js +1 -1
- package/out/zero-cache/src/services/change-source/change-source.d.ts +7 -0
- package/out/zero-cache/src/services/change-source/change-source.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.js +1 -1
- package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.js.map +1 -1
- package/out/zero-cache/src/services/change-source/custom/change-source.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/custom/change-source.js +3 -0
- package/out/zero-cache/src/services/change-source/custom/change-source.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source.d.ts +9 -1
- package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source.js +150 -45
- package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts +8 -0
- package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/status.d.ts +26 -1
- package/out/zero-cache/src/services/change-source/protocol/current/status.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/status.js +7 -2
- package/out/zero-cache/src/services/change-source/protocol/current/status.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/upstream.d.ts +8 -0
- package/out/zero-cache/src/services/change-source/protocol/current/upstream.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +10 -2
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts +25 -0
- package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer.js +8 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/forwarder.d.ts +2 -0
- package/out/zero-cache/src/services/change-streamer/forwarder.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/forwarder.js +3 -0
- package/out/zero-cache/src/services/change-streamer/forwarder.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/subscriber.d.ts +3 -2
- package/out/zero-cache/src/services/change-streamer/subscriber.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/subscriber.js +17 -8
- package/out/zero-cache/src/services/change-streamer/subscriber.js.map +1 -1
- package/out/zero-cache/src/services/replicator/incremental-sync.d.ts +2 -2
- package/out/zero-cache/src/services/replicator/incremental-sync.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/incremental-sync.js +19 -4
- package/out/zero-cache/src/services/replicator/incremental-sync.js.map +1 -1
- package/out/zero-cache/src/services/replicator/replicator.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/replicator.js +2 -2
- package/out/zero-cache/src/services/replicator/replicator.js.map +1 -1
- package/out/zero-cache/src/services/replicator/reporter/recorder.d.ts +12 -0
- package/out/zero-cache/src/services/replicator/reporter/recorder.d.ts.map +1 -0
- package/out/zero-cache/src/services/replicator/reporter/recorder.js +58 -0
- package/out/zero-cache/src/services/replicator/reporter/recorder.js.map +1 -0
- package/out/zero-cache/src/services/replicator/reporter/report-schema.d.ts +35 -0
- package/out/zero-cache/src/services/replicator/reporter/report-schema.d.ts.map +1 -0
- package/out/zero-cache/src/services/replicator/reporter/report-schema.js +20 -0
- package/out/zero-cache/src/services/replicator/reporter/report-schema.js.map +1 -0
- package/out/zero-cache/src/services/run-ast.js +1 -1
- package/out/zero-cache/src/types/pg.d.ts.map +1 -1
- package/out/zero-cache/src/types/pg.js +2 -0
- package/out/zero-cache/src/types/pg.js.map +1 -1
- package/out/zero-client/src/client/version.js +1 -1
- package/package.json +1 -1
- package/out/analyze-query/src/run-ast.d.ts +0 -22
- package/out/analyze-query/src/run-ast.d.ts.map +0 -1
- package/out/analyze-query/src/run-ast.js +0 -75
- package/out/analyze-query/src/run-ast.js.map +0 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { assert } from "../../../../../shared/src/asserts.js";
|
|
1
2
|
import { deepEqual } from "../../../../../shared/src/json.js";
|
|
2
|
-
import { promiseVoid } from "../../../../../shared/src/resolved-promises.js";
|
|
3
3
|
import { AbortError } from "../../../../../shared/src/abort-error.js";
|
|
4
4
|
import { sleep } from "../../../../../shared/src/sleep.js";
|
|
5
|
-
import { parse } from "../../../../../shared/src/valita.js";
|
|
5
|
+
import { parse, valita_exports } from "../../../../../shared/src/valita.js";
|
|
6
6
|
import { must } from "../../../../../shared/src/must.js";
|
|
7
7
|
import { mapValues } from "../../../../../shared/src/objects.js";
|
|
8
8
|
import { equals, intersection, symmetricDifferences } from "../../../../../shared/src/set-utils.js";
|
|
@@ -29,6 +29,7 @@ import { initialSync } from "./initial-sync.js";
|
|
|
29
29
|
import { streamBackfill } from "./backfill-stream.js";
|
|
30
30
|
import { subscribe } from "./logical-replication/stream.js";
|
|
31
31
|
import postgres from "postgres";
|
|
32
|
+
import { nanoid } from "nanoid";
|
|
32
33
|
import { PG_ADMIN_SHUTDOWN, PG_OBJECT_IN_USE } from "@drdgvhbh/postgres-error-codes";
|
|
33
34
|
//#region ../zero-cache/src/services/change-source/pg/change-source.ts
|
|
34
35
|
/**
|
|
@@ -36,7 +37,7 @@ import { PG_ADMIN_SHUTDOWN, PG_OBJECT_IN_USE } from "@drdgvhbh/postgres-error-co
|
|
|
36
37
|
* replica, before streaming changes from the corresponding logical replication
|
|
37
38
|
* stream.
|
|
38
39
|
*/
|
|
39
|
-
async function initializePostgresChangeSource(lc, upstreamURI, shard, replicaDbFile, syncOptions, context) {
|
|
40
|
+
async function initializePostgresChangeSource(lc, upstreamURI, shard, replicaDbFile, syncOptions, context, lagReportIntervalMs) {
|
|
40
41
|
await initReplica(lc, `replica-${shard.appID}-${shard.shardNum}`, replicaDbFile, (log, tx) => initialSync(log, shard, tx, upstreamURI, syncOptions, context));
|
|
41
42
|
const replica = new Database(lc, replicaDbFile);
|
|
42
43
|
const subscriptionState = getSubscriptionStateAndContext(new StatementRunner(replica));
|
|
@@ -45,7 +46,7 @@ async function initializePostgresChangeSource(lc, upstreamURI, shard, replicaDbF
|
|
|
45
46
|
try {
|
|
46
47
|
return {
|
|
47
48
|
subscriptionState,
|
|
48
|
-
changeSource: new PostgresChangeSource(lc, upstreamURI, shard, await checkAndUpdateUpstream(lc, db, shard, subscriptionState), context)
|
|
49
|
+
changeSource: new PostgresChangeSource(lc, upstreamURI, shard, await checkAndUpdateUpstream(lc, db, shard, subscriptionState), context, lagReportIntervalMs ?? null)
|
|
49
50
|
};
|
|
50
51
|
} finally {
|
|
51
52
|
await db.end();
|
|
@@ -83,50 +84,68 @@ var MAX_LOW_PRIORITY_DELAY_MS = 1e3;
|
|
|
83
84
|
*/
|
|
84
85
|
var PostgresChangeSource = class {
|
|
85
86
|
#lc;
|
|
87
|
+
#db;
|
|
86
88
|
#upstreamUri;
|
|
87
89
|
#shard;
|
|
88
90
|
#replica;
|
|
89
91
|
#context;
|
|
90
|
-
|
|
92
|
+
#lagReporter;
|
|
93
|
+
constructor(lc, upstreamUri, shard, replica, context, lagReportIntervalMs) {
|
|
91
94
|
this.#lc = lc.withContext("component", "change-source");
|
|
95
|
+
this.#db = pgClient(lc, upstreamUri, {
|
|
96
|
+
["idle_timeout"]: 60,
|
|
97
|
+
connection: { ["application_name"]: "zero-replication-monitor" }
|
|
98
|
+
});
|
|
92
99
|
this.#upstreamUri = upstreamUri;
|
|
93
100
|
this.#shard = shard;
|
|
94
101
|
this.#replica = replica;
|
|
95
102
|
this.#context = context;
|
|
103
|
+
this.#lagReporter = lagReportIntervalMs ? new LagReporter(lc.withContext("component", "lag-reporter"), shard, this.#db, lagReportIntervalMs) : null;
|
|
104
|
+
}
|
|
105
|
+
startLagReporter() {
|
|
106
|
+
return this.#lagReporter ? this.#lagReporter.initiateLagReport() : null;
|
|
96
107
|
}
|
|
97
108
|
async startStream(clientWatermark, backfillRequests = []) {
|
|
98
|
-
const db = pgClient(this.#lc, this.#upstreamUri);
|
|
99
109
|
const { slot } = this.#replica;
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
this.#lc.info?.(`starting replication stream@${slot}`);
|
|
105
|
-
return await this.#startStream(db, slot, clientWatermark, config, backfillRequests);
|
|
106
|
-
} finally {
|
|
107
|
-
cleanup.then(() => db.end());
|
|
108
|
-
}
|
|
110
|
+
await this.#stopExistingReplicationSlotSubscribers(slot);
|
|
111
|
+
const config = await getInternalShardConfig(this.#db, this.#shard);
|
|
112
|
+
this.#lc.info?.(`starting replication stream@${slot}`);
|
|
113
|
+
return this.#startStream(slot, clientWatermark, config, backfillRequests);
|
|
109
114
|
}
|
|
110
|
-
async #startStream(
|
|
115
|
+
async #startStream(slot, clientWatermark, shardConfig, backfillRequests) {
|
|
111
116
|
const clientStart = majorVersionFromString(clientWatermark) + 1n;
|
|
112
|
-
const { messages, acks } = await subscribe(this.#lc, db, slot, [...shardConfig.publications], clientStart);
|
|
117
|
+
const { messages, acks } = await subscribe(this.#lc, this.#db, slot, [...shardConfig.publications], clientStart);
|
|
113
118
|
const acker = new Acker(acks);
|
|
114
119
|
const changes = new ChangeStreamMultiplexer(this.#lc, clientWatermark);
|
|
115
120
|
const backfillManager = new BackfillManager(this.#lc, changes, (req) => streamBackfill(this.#lc, this.#upstreamUri, this.#replica, req));
|
|
116
121
|
changes.addProducers(messages, backfillManager).addListeners(backfillManager, acker);
|
|
117
122
|
backfillManager.run(clientWatermark, backfillRequests);
|
|
118
|
-
const changeMaker = new ChangeMaker(this.#lc, this.#shard, shardConfig, this.#
|
|
123
|
+
const changeMaker = new ChangeMaker(this.#lc, this.#shard, shardConfig, this.#db, this.#replica.initialSchema);
|
|
124
|
+
/**
|
|
125
|
+
* Determines if the incoming message is transactional, otherwise handling
|
|
126
|
+
* non-transactional messages with a downstream status message.
|
|
127
|
+
*/
|
|
128
|
+
const isTransactionalMessage = (lsn, msg) => {
|
|
129
|
+
if (msg.tag === "keepalive") {
|
|
130
|
+
changes.pushStatus([
|
|
131
|
+
"status",
|
|
132
|
+
{ ack: msg.shouldRespond },
|
|
133
|
+
{ watermark: majorVersionToString(lsn) }
|
|
134
|
+
]);
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
if (msg.tag === "message" && msg.prefix === this.#lagReporter?.messagePrefix) {
|
|
138
|
+
changes.pushStatus(this.#lagReporter.processLagReport(msg));
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
return true;
|
|
142
|
+
};
|
|
119
143
|
(async () => {
|
|
120
144
|
try {
|
|
121
145
|
let reservation = null;
|
|
122
146
|
let inTransaction = false;
|
|
123
147
|
for await (const [lsn, msg] of messages) {
|
|
124
|
-
if (msg
|
|
125
|
-
changes.pushStatus([
|
|
126
|
-
"status",
|
|
127
|
-
{ ack: msg.shouldRespond },
|
|
128
|
-
{ watermark: majorVersionToString(lsn) }
|
|
129
|
-
]);
|
|
148
|
+
if (!isTransactionalMessage(lsn, msg)) {
|
|
130
149
|
if (!inTransaction && reservation?.lastWatermark) {
|
|
131
150
|
changes.release(reservation.lastWatermark);
|
|
132
151
|
reservation = null;
|
|
@@ -170,14 +189,11 @@ var PostgresChangeSource = class {
|
|
|
170
189
|
};
|
|
171
190
|
}
|
|
172
191
|
async #logCurrentReplicaInfo() {
|
|
173
|
-
const db = pgClient(this.#lc, this.#upstreamUri);
|
|
174
192
|
try {
|
|
175
|
-
const replica = await getReplicaAtVersion(this.#lc, db, this.#shard, this.#replica.version);
|
|
193
|
+
const replica = await getReplicaAtVersion(this.#lc, this.#db, this.#shard, this.#replica.version);
|
|
176
194
|
if (replica) this.#lc.info?.(`Shutdown signal from replica@${this.#replica.version}: ${stringify(replica.subscriberContext)}`);
|
|
177
195
|
} catch (e) {
|
|
178
196
|
this.#lc.warn?.(`error logging replica info`, e);
|
|
179
|
-
} finally {
|
|
180
|
-
await db.end();
|
|
181
197
|
}
|
|
182
198
|
}
|
|
183
199
|
/**
|
|
@@ -189,10 +205,10 @@ var PostgresChangeSource = class {
|
|
|
189
205
|
* the timestamp suffix) are preserved, as those are newly syncing replicas
|
|
190
206
|
* that will soon take over the slot.
|
|
191
207
|
*/
|
|
192
|
-
async #stopExistingReplicationSlotSubscribers(
|
|
208
|
+
async #stopExistingReplicationSlotSubscribers(slotToKeep) {
|
|
193
209
|
const slotExpression = replicationSlotExpression(this.#shard);
|
|
194
210
|
const legacySlotName = legacyReplicationSlot(this.#shard);
|
|
195
|
-
const result = await runTx(db, async (sql) => {
|
|
211
|
+
const result = await runTx(this.#db, async (sql) => {
|
|
196
212
|
const result = await sql`
|
|
197
213
|
SELECT slot_name as slot, pg_terminate_backend(active_pid) as terminated, active_pid as pid
|
|
198
214
|
FROM pg_replication_slots
|
|
@@ -230,10 +246,11 @@ var PostgresChangeSource = class {
|
|
|
230
246
|
const pids = result.filter(({ pid }) => pid !== null).map(({ pid }) => pid);
|
|
231
247
|
if (pids.length) this.#lc.info?.(`signaled subscriber ${pids} to shut down`);
|
|
232
248
|
const otherSlots = result.filter(({ slot }) => slot !== slotToKeep).map(({ slot }) => slot);
|
|
233
|
-
|
|
249
|
+
if (otherSlots.length) this.#dropReplicationSlots(otherSlots).catch((e) => this.#lc.warn?.(`error dropping replication slots`, e));
|
|
234
250
|
}
|
|
235
|
-
async #dropReplicationSlots(
|
|
251
|
+
async #dropReplicationSlots(slots) {
|
|
236
252
|
this.#lc.info?.(`dropping other replication slot(s) ${slots}`);
|
|
253
|
+
const sql = this.#db;
|
|
237
254
|
for (let i = 0; i < 5; i++) try {
|
|
238
255
|
await sql`
|
|
239
256
|
SELECT pg_drop_replication_slot(slot_name) FROM pg_replication_slots
|
|
@@ -282,24 +299,112 @@ var Acker = class {
|
|
|
282
299
|
this.#acks.push(lsn);
|
|
283
300
|
}
|
|
284
301
|
};
|
|
302
|
+
var lagReportSchema = valita_exports.object({
|
|
303
|
+
id: valita_exports.string(),
|
|
304
|
+
sendTimeMs: valita_exports.number(),
|
|
305
|
+
commitTimeMs: valita_exports.number()
|
|
306
|
+
});
|
|
307
|
+
var LagReporter = class LagReporter {
|
|
308
|
+
static MESSAGE_SUFFIX = "/lag-report/v1";
|
|
309
|
+
#lc;
|
|
310
|
+
messagePrefix;
|
|
311
|
+
#db;
|
|
312
|
+
#lagIntervalMs;
|
|
313
|
+
#pgVersion;
|
|
314
|
+
#lastReportID = "";
|
|
315
|
+
#timer;
|
|
316
|
+
constructor(lc, shard, db, lagIntervalMs) {
|
|
317
|
+
this.#lc = lc;
|
|
318
|
+
this.messagePrefix = `${shard.appID}/${shard.shardNum}${LagReporter.MESSAGE_SUFFIX}`;
|
|
319
|
+
this.#db = db;
|
|
320
|
+
this.#lagIntervalMs = lagIntervalMs;
|
|
321
|
+
}
|
|
322
|
+
async #getPgVersion() {
|
|
323
|
+
if (this.#pgVersion === void 0) {
|
|
324
|
+
const [{ pgVersion }] = await this.#db`
|
|
325
|
+
SELECT current_setting('server_version_num')::int as "pgVersion"`;
|
|
326
|
+
this.#pgVersion = pgVersion;
|
|
327
|
+
}
|
|
328
|
+
return this.#pgVersion;
|
|
329
|
+
}
|
|
330
|
+
async initiateLagReport(now = Date.now()) {
|
|
331
|
+
const pgVersion = this.#pgVersion ?? await this.#getPgVersion();
|
|
332
|
+
this.#lastReportID = nanoid();
|
|
333
|
+
if (pgVersion >= 17e4) await this.#db`
|
|
334
|
+
SELECT pg_logical_emit_message(
|
|
335
|
+
false,
|
|
336
|
+
${this.messagePrefix},
|
|
337
|
+
json_build_object(
|
|
338
|
+
'id', ${this.#lastReportID}::text,
|
|
339
|
+
'sendTimeMs', ${now}::int8,
|
|
340
|
+
'commitTimeMs', extract(epoch from now()) * 1000
|
|
341
|
+
)::text,
|
|
342
|
+
true
|
|
343
|
+
);
|
|
344
|
+
`;
|
|
345
|
+
else await this.#db`
|
|
346
|
+
SELECT pg_logical_emit_message(
|
|
347
|
+
false,
|
|
348
|
+
${this.messagePrefix},
|
|
349
|
+
json_build_object(
|
|
350
|
+
'id', ${this.#lastReportID}::text,
|
|
351
|
+
'sendTimeMs', ${now}::int8,
|
|
352
|
+
'commitTimeMs', extract(epoch from now()) * 1000
|
|
353
|
+
)::text
|
|
354
|
+
);
|
|
355
|
+
`;
|
|
356
|
+
return { nextSendTimeMs: now };
|
|
357
|
+
}
|
|
358
|
+
#scheduleNextReport(delayMs) {
|
|
359
|
+
clearTimeout(this.#timer);
|
|
360
|
+
this.#timer = setTimeout(async () => {
|
|
361
|
+
try {
|
|
362
|
+
await this.initiateLagReport();
|
|
363
|
+
} catch (e) {
|
|
364
|
+
this.#lc.warn?.(`error initiating lag report`, e);
|
|
365
|
+
this.#scheduleNextReport(this.#lagIntervalMs);
|
|
366
|
+
}
|
|
367
|
+
}, delayMs);
|
|
368
|
+
}
|
|
369
|
+
processLagReport(msg) {
|
|
370
|
+
assert(msg.prefix === this.messagePrefix, `unexpected message prefix: ${msg.prefix}`);
|
|
371
|
+
const report = parseLogicalMessageContent(msg, lagReportSchema);
|
|
372
|
+
const now = Date.now();
|
|
373
|
+
const nextSendTimeMs = Math.max(now, report.sendTimeMs + this.#lagIntervalMs);
|
|
374
|
+
if (report.id === this.#lastReportID) this.#scheduleNextReport(nextSendTimeMs - now);
|
|
375
|
+
const { sendTimeMs, commitTimeMs } = report;
|
|
376
|
+
return [
|
|
377
|
+
"status",
|
|
378
|
+
{
|
|
379
|
+
ack: false,
|
|
380
|
+
lagReport: {
|
|
381
|
+
lastTimings: {
|
|
382
|
+
sendTimeMs,
|
|
383
|
+
commitTimeMs,
|
|
384
|
+
receiveTimeMs: now
|
|
385
|
+
},
|
|
386
|
+
nextSendTimeMs
|
|
387
|
+
}
|
|
388
|
+
},
|
|
389
|
+
{ watermark: toStateVersionString(msg.messageLsn ?? "0/0") }
|
|
390
|
+
];
|
|
391
|
+
}
|
|
392
|
+
};
|
|
285
393
|
var SET_REPLICA_IDENTITY_DELAY_MS = 50;
|
|
286
394
|
var ChangeMaker = class {
|
|
287
395
|
#lc;
|
|
288
396
|
#shardPrefix;
|
|
289
397
|
#shardConfig;
|
|
290
398
|
#initialSchema;
|
|
291
|
-
#
|
|
399
|
+
#db;
|
|
292
400
|
#replicaIdentityTimer;
|
|
293
401
|
#error;
|
|
294
|
-
constructor(lc, { appID, shardNum }, shardConfig,
|
|
402
|
+
constructor(lc, { appID, shardNum }, shardConfig, db, initialSchema) {
|
|
295
403
|
this.#lc = lc;
|
|
296
404
|
this.#shardPrefix = `${appID}/${shardNum}`;
|
|
297
405
|
this.#shardConfig = shardConfig;
|
|
298
406
|
this.#initialSchema = initialSchema;
|
|
299
|
-
this.#
|
|
300
|
-
["idle_timeout"]: 10,
|
|
301
|
-
connection: { ["application_name"]: "zero-schema-change-detector" }
|
|
302
|
-
});
|
|
407
|
+
this.#db = db;
|
|
303
408
|
}
|
|
304
409
|
async makeChanges(lsn, msg) {
|
|
305
410
|
if (this.#error) {
|
|
@@ -398,7 +503,7 @@ var ChangeMaker = class {
|
|
|
398
503
|
#preSchema;
|
|
399
504
|
#lastSnapshotInTx;
|
|
400
505
|
#handleDdlMessage(msg) {
|
|
401
|
-
const event =
|
|
506
|
+
const event = parseLogicalMessageContent(msg, replicationEventSchema);
|
|
402
507
|
clearTimeout(this.#replicaIdentityTimer);
|
|
403
508
|
let previousSchema;
|
|
404
509
|
const { type } = event;
|
|
@@ -427,7 +532,7 @@ var ChangeMaker = class {
|
|
|
427
532
|
const replicaIdentities = replicaIdentitiesForTablesWithoutPrimaryKeys(event.schema);
|
|
428
533
|
if (replicaIdentities) this.#replicaIdentityTimer = setTimeout(async () => {
|
|
429
534
|
try {
|
|
430
|
-
await replicaIdentities.apply(this.#lc, this.#
|
|
535
|
+
await replicaIdentities.apply(this.#lc, this.#db);
|
|
431
536
|
} catch (err) {
|
|
432
537
|
this.#lc.warn?.(`error setting replica identities`, err);
|
|
433
538
|
}
|
|
@@ -602,10 +707,6 @@ var ChangeMaker = class {
|
|
|
602
707
|
}
|
|
603
708
|
return changes;
|
|
604
709
|
}
|
|
605
|
-
#parseReplicationEvent(content) {
|
|
606
|
-
const str = content instanceof Buffer ? content.toString("utf-8") : new TextDecoder().decode(content);
|
|
607
|
-
return parse(JSON.parse(str), replicationEventSchema, "passthrough");
|
|
608
|
-
}
|
|
609
710
|
/**
|
|
610
711
|
* If `ddlDetection === true`, relation messages are irrelevant,
|
|
611
712
|
* as schema changes are detected by event triggers that
|
|
@@ -627,7 +728,7 @@ var ChangeMaker = class {
|
|
|
627
728
|
async #handleRelation(rel) {
|
|
628
729
|
const { publications, ddlDetection } = this.#shardConfig;
|
|
629
730
|
if (ddlDetection) return [];
|
|
630
|
-
const currentSchema = await getPublicationInfo(this.#
|
|
731
|
+
const currentSchema = await getPublicationInfo(this.#db, publications);
|
|
631
732
|
const difference = getSchemaDifference(this.#initialSchema, currentSchema);
|
|
632
733
|
if (difference !== null) throw new MissingEventTriggerSupport(difference);
|
|
633
734
|
const orel = this.#initialSchema.tables.find((t) => t.oid === rel.relationOid);
|
|
@@ -752,6 +853,10 @@ var ShutdownSignal = class extends AbortError {
|
|
|
752
853
|
super("shutdown signal received (e.g. another zero-cache taking over the replication stream)", { cause });
|
|
753
854
|
}
|
|
754
855
|
};
|
|
856
|
+
function parseLogicalMessageContent({ content }, schema) {
|
|
857
|
+
const str = content instanceof Buffer ? content.toString("utf-8") : new TextDecoder().decode(content);
|
|
858
|
+
return parse(JSON.parse(str), schema, "passthrough");
|
|
859
|
+
}
|
|
755
860
|
//#endregion
|
|
756
861
|
export { initializePostgresChangeSource };
|
|
757
862
|
|