@nodii/telemetry 0.13.0 → 0.14.1
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/dist/worker/checkpoint-store.d.ts +66 -0
- package/dist/worker/checkpoint-store.d.ts.map +1 -0
- package/dist/worker/checkpoint-store.js +131 -0
- package/dist/worker/checkpoint-store.js.map +1 -0
- package/dist/worker/dead-letter.d.ts +81 -0
- package/dist/worker/dead-letter.d.ts.map +1 -0
- package/dist/worker/dead-letter.js +165 -0
- package/dist/worker/dead-letter.js.map +1 -0
- package/dist/worker/dedupe-store.d.ts +46 -0
- package/dist/worker/dedupe-store.d.ts.map +1 -0
- package/dist/worker/dedupe-store.js +113 -0
- package/dist/worker/dedupe-store.js.map +1 -0
- package/dist/worker/index.d.ts +23 -0
- package/dist/worker/index.d.ts.map +1 -0
- package/dist/worker/index.js +46 -0
- package/dist/worker/index.js.map +1 -0
- package/dist/worker/observability-hooks.d.ts +99 -0
- package/dist/worker/observability-hooks.d.ts.map +1 -0
- package/dist/worker/observability-hooks.js +189 -0
- package/dist/worker/observability-hooks.js.map +1 -0
- package/dist/worker/outbox-dispatcher.d.ts +106 -0
- package/dist/worker/outbox-dispatcher.d.ts.map +1 -0
- package/dist/worker/outbox-dispatcher.js +285 -0
- package/dist/worker/outbox-dispatcher.js.map +1 -0
- package/dist/worker/replication-worker.d.ts +170 -0
- package/dist/worker/replication-worker.d.ts.map +1 -0
- package/dist/worker/replication-worker.js +576 -0
- package/dist/worker/replication-worker.js.map +1 -0
- package/dist/worker/signal-drain.d.ts +83 -0
- package/dist/worker/signal-drain.d.ts.map +1 -0
- package/dist/worker/signal-drain.js +131 -0
- package/dist/worker/signal-drain.js.map +1 -0
- package/dist/worker/single-active-lease.d.ts +180 -0
- package/dist/worker/single-active-lease.d.ts.map +1 -0
- package/dist/worker/single-active-lease.js +394 -0
- package/dist/worker/single-active-lease.js.map +1 -0
- package/dist/worker/streams-worker.d.ts +256 -0
- package/dist/worker/streams-worker.d.ts.map +1 -0
- package/dist/worker/streams-worker.js +621 -0
- package/dist/worker/streams-worker.js.map +1 -0
- package/dist/worker/sweeper-worker.d.ts +107 -0
- package/dist/worker/sweeper-worker.d.ts.map +1 -0
- package/dist/worker/sweeper-worker.js +245 -0
- package/dist/worker/sweeper-worker.js.map +1 -0
- package/dist/worker/tx.d.ts +39 -0
- package/dist/worker/tx.d.ts.map +1 -0
- package/dist/worker/tx.js +51 -0
- package/dist/worker/tx.js.map +1 -0
- package/dist/worker/worker-handle.d.ts +94 -0
- package/dist/worker/worker-handle.d.ts.map +1 -0
- package/dist/worker/worker-handle.js +15 -0
- package/dist/worker/worker-handle.js.map +1 -0
- package/package.json +6 -1
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
// D402 — OutboxDispatcher: the Pattern-3 PRODUCER drain.
|
|
2
|
+
//
|
|
3
|
+
// D402 (LOCKED): "OutboxDispatcher — Pattern-3 producer drain." It GENERALIZES
|
|
4
|
+
// the pattern shipped in `ts/outbox-dispatcher/src/drainer.ts` (which this lib
|
|
5
|
+
// does NOT edit — outbox-dispatcher gets re-based onto this substrate in
|
|
6
|
+
// Phase 2). The producer side of the both-sides-completeness rule: every outbox
|
|
7
|
+
// topic has a standardized producer (this) AND a standardized consumer
|
|
8
|
+
// (StreamsWorker / ReplicationWorker).
|
|
9
|
+
//
|
|
10
|
+
// ── Composition (which primitives, how) ──────────────────────────────────────
|
|
11
|
+
// - SingleActiveLease — single-active per (service, outbox) so two dispatcher
|
|
12
|
+
// replicas don't both drain. ttl/2 renew inside the lease. `validateFence`
|
|
13
|
+
// guards the mark-dispatched write (a lease-lost dispatcher's late mark is
|
|
14
|
+
// rejected — it must not mark a row another dispatcher is publishing).
|
|
15
|
+
// - CheckpointStore — tracks the HWM (the last published stream id) so the
|
|
16
|
+
// `nodii.worker.current_hwm` gauge + resume position are durable. The mark
|
|
17
|
+
// UPDATE and the cursor advance run in the SAME claim tx (atomic).
|
|
18
|
+
// - ObservabilityHooks — lease/hwm/depth/drain metrics, canonical names.
|
|
19
|
+
// - SignalDrain — `stop({timeoutMs})` registerable; bounded drain.
|
|
20
|
+
// - DeadLetterSink — OPTIONAL and currently NOT invoked on any path. Per
|
|
21
|
+
// D401 the producer drain has NO source-side dead-letter: a terminal /
|
|
22
|
+
// unpublishable row is surfaced via `recordFailure` (keep-row,
|
|
23
|
+
// publish_attempts bumped) + the 24h-unpublished sweep, NOT a sink. The sink
|
|
24
|
+
// is accepted for API symmetry with the consumer workers + a future opt-in
|
|
25
|
+
// (PII-redacted if provided), but no drain path calls it today.
|
|
26
|
+
//
|
|
27
|
+
// ── The drain sequence (per 01-comms § 9.2 / outbox-dispatcher § 5.2) ─────────
|
|
28
|
+
// acquire-lease → claim a batch (dispatched_at IS NULL, occurred_at order,
|
|
29
|
+
// FOR UPDATE SKIP LOCKED) inside a tx → publish each (injected publisher) →
|
|
30
|
+
// mark dispatched (fence-guarded) + advance the HWM cursor, all in the SAME
|
|
31
|
+
// tx → commit. D401: a publish failure increments attempts + leaves the row in
|
|
32
|
+
// place (never DLQ).
|
|
33
|
+
//
|
|
34
|
+
// ── At-least-once semantics (NOT exactly-once on the producer side) ───────────
|
|
35
|
+
// The PUBLISH (XADD) runs BEFORE `validateFence` — it is NOT fenced. A stale or
|
|
36
|
+
// retried dispatcher's publish therefore DOES land: the producer is
|
|
37
|
+
// AT-LEAST-ONCE (the same row may be re-published after a crash-before-commit
|
|
38
|
+
// or a lease handoff). The fence guards only the mark-dispatched UPDATE — it
|
|
39
|
+
// stops a lease-lost dispatcher from falsely recording a row as dispatched
|
|
40
|
+
// (which would suppress the legitimate successor's re-publish). END-TO-END
|
|
41
|
+
// exactly-once is achieved by the CONSUMER's `consumed_events` dedupe (D198),
|
|
42
|
+
// NOT by the fence preventing the publish.
|
|
43
|
+
import { ensurePiiRedaction } from "./dead-letter.js";
|
|
44
|
+
import { hwmGaugeValue, ObservabilityHooks } from "./observability-hooks.js";
|
|
45
|
+
import { FenceCheckUnavailableError, FenceLostError, SingleActiveLease, } from "./single-active-lease.js";
|
|
46
|
+
const DEFAULT_BATCH_SIZE = 100;
|
|
47
|
+
const DEFAULT_POLL_MS = 1_000;
|
|
48
|
+
const DEFAULT_STOP_TIMEOUT_MS = 30_000;
|
|
49
|
+
/**
|
|
50
|
+
* OutboxDispatcher — the Pattern-3 producer drain. Composes lease + checkpoint +
|
|
51
|
+
* hooks + drain. Single-active; the mark-dispatched + cursor advance are atomic
|
|
52
|
+
* in the claim tx; publish is at-least-once (the consumer dedupes).
|
|
53
|
+
*/
|
|
54
|
+
export class OutboxDispatcher {
|
|
55
|
+
publish;
|
|
56
|
+
begin;
|
|
57
|
+
claimBatch;
|
|
58
|
+
markDispatched;
|
|
59
|
+
recordFailure;
|
|
60
|
+
checkpoint;
|
|
61
|
+
lease;
|
|
62
|
+
subscription;
|
|
63
|
+
// OPTIONAL + currently uninvoked (see the opts docstring). Kept for API
|
|
64
|
+
// symmetry / a future opt-in; PII-redacted if provided.
|
|
65
|
+
deadLetter;
|
|
66
|
+
batchSize;
|
|
67
|
+
pollMs;
|
|
68
|
+
hooks;
|
|
69
|
+
autoStart;
|
|
70
|
+
_running = false;
|
|
71
|
+
_stopped = false;
|
|
72
|
+
_inFlight = 0;
|
|
73
|
+
_hwm = { lastStreamId: null };
|
|
74
|
+
_lastAppliedAtMs = null;
|
|
75
|
+
loop = Promise.resolve();
|
|
76
|
+
constructor(opts) {
|
|
77
|
+
this.publish = opts.publish;
|
|
78
|
+
this.begin = opts.begin;
|
|
79
|
+
this.claimBatch = opts.claimBatch;
|
|
80
|
+
this.markDispatched = opts.markDispatched;
|
|
81
|
+
this.recordFailure = opts.recordFailure;
|
|
82
|
+
this.checkpoint = opts.checkpoint;
|
|
83
|
+
this.lease = new SingleActiveLease({
|
|
84
|
+
...opts.lease,
|
|
85
|
+
onLeaseLost: () => this.hooks.leaseLost(),
|
|
86
|
+
});
|
|
87
|
+
this.subscription = opts.subscription ?? `outbox:${opts.lease.service}`;
|
|
88
|
+
this.deadLetter = opts.deadLetter
|
|
89
|
+
? ensurePiiRedaction(opts.deadLetter)
|
|
90
|
+
: undefined;
|
|
91
|
+
this.batchSize = opts.batchSize ?? DEFAULT_BATCH_SIZE;
|
|
92
|
+
this.pollMs = opts.pollMs ?? DEFAULT_POLL_MS;
|
|
93
|
+
this.autoStart = opts.autoStart !== false;
|
|
94
|
+
this.hooks =
|
|
95
|
+
opts.hooks ??
|
|
96
|
+
new ObservabilityHooks({
|
|
97
|
+
attributes: {
|
|
98
|
+
service: opts.lease.service,
|
|
99
|
+
scope: opts.lease.scope,
|
|
100
|
+
worker: opts.workerLabel ?? "outbox",
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
get running() {
|
|
105
|
+
return this._running;
|
|
106
|
+
}
|
|
107
|
+
get leaseAcquired() {
|
|
108
|
+
return this.lease.leaseAcquired;
|
|
109
|
+
}
|
|
110
|
+
get lag() {
|
|
111
|
+
if (this._lastAppliedAtMs === null)
|
|
112
|
+
return null;
|
|
113
|
+
return Math.max(0, (Date.now() - this._lastAppliedAtMs) / 1000);
|
|
114
|
+
}
|
|
115
|
+
get currentHwm() {
|
|
116
|
+
return this._hwm;
|
|
117
|
+
}
|
|
118
|
+
async start() {
|
|
119
|
+
if (this._running)
|
|
120
|
+
return;
|
|
121
|
+
this._stopped = false;
|
|
122
|
+
const acquired = await this.lease.acquire();
|
|
123
|
+
if (acquired)
|
|
124
|
+
this.hooks.leaseAcquired();
|
|
125
|
+
await this.hydrateCursor();
|
|
126
|
+
this._running = true;
|
|
127
|
+
// Background drain loop. `autoStart:false` lets a test drive `drainOnce()`.
|
|
128
|
+
if (this.autoStart)
|
|
129
|
+
this.loop = this.runLoop();
|
|
130
|
+
}
|
|
131
|
+
async hydrateCursor() {
|
|
132
|
+
try {
|
|
133
|
+
await this.begin(async (tx) => {
|
|
134
|
+
const cp = await this.checkpoint.get(this.subscription, tx);
|
|
135
|
+
if (cp)
|
|
136
|
+
this._hwm = { lastStreamId: cp.lastStreamId };
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
/* cold start — cursor stays null */
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
async runLoop() {
|
|
144
|
+
while (!this._stopped) {
|
|
145
|
+
try {
|
|
146
|
+
if (!this.lease.leaseAcquired) {
|
|
147
|
+
const got = await this.lease.acquire();
|
|
148
|
+
if (got)
|
|
149
|
+
this.hooks.leaseAcquired();
|
|
150
|
+
else {
|
|
151
|
+
await new Promise((r) => setTimeout(r, this.pollMs));
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
const n = await this.drainOnce();
|
|
156
|
+
if (n < this.batchSize) {
|
|
157
|
+
await new Promise((r) => setTimeout(r, this.pollMs));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
catch (err) {
|
|
161
|
+
// A drain-level error (claim tx itself rejected — Postgres down) is the
|
|
162
|
+
// Pillar-5 infra-failure case: back off, NEVER crash the loop.
|
|
163
|
+
this.hooks.recordDepth(-1, { error: "drain_failed" });
|
|
164
|
+
void err;
|
|
165
|
+
await new Promise((r) => setTimeout(r, Math.min(this.pollMs, 200)));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* One drain pass: claim a batch in ONE tx, publish each, mark dispatched +
|
|
171
|
+
* advance the HWM cursor (fence-guarded) in the SAME tx. Returns the count
|
|
172
|
+
* dispatched. The publish runs INSIDE the claim tx so the row-lock is held
|
|
173
|
+
* across it (a second dispatcher can't double-claim); at-least-once safe (a
|
|
174
|
+
* crash after publish but before commit re-publishes; the consumer dedupes).
|
|
175
|
+
*/
|
|
176
|
+
async drainOnce() {
|
|
177
|
+
if (!this.lease.leaseAcquired) {
|
|
178
|
+
const got = await this.lease.acquire();
|
|
179
|
+
if (got)
|
|
180
|
+
this.hooks.leaseAcquired();
|
|
181
|
+
else
|
|
182
|
+
return 0;
|
|
183
|
+
}
|
|
184
|
+
const token = this.lease.fencingToken;
|
|
185
|
+
let dispatched = 0;
|
|
186
|
+
let lastStreamId = null;
|
|
187
|
+
await this.begin(async (tx) => {
|
|
188
|
+
const rows = await this.claimBatch(tx, this.batchSize);
|
|
189
|
+
if (rows.length === 0)
|
|
190
|
+
return;
|
|
191
|
+
for (const row of rows) {
|
|
192
|
+
if (this.lease.lost)
|
|
193
|
+
break;
|
|
194
|
+
this._inFlight += 1;
|
|
195
|
+
let fenceLost = false;
|
|
196
|
+
try {
|
|
197
|
+
const streamId = await this.publish(row);
|
|
198
|
+
// The fence guard BEFORE marking the row dispatched: a lease-lost
|
|
199
|
+
// dispatcher must not mark a row a successor is also publishing.
|
|
200
|
+
if (token === null) {
|
|
201
|
+
throw new FenceLostError({
|
|
202
|
+
leaseKey: this.lease.key,
|
|
203
|
+
expectedToken: -1,
|
|
204
|
+
current: null,
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
await this.lease.validateFence(token);
|
|
208
|
+
await this.markDispatched(tx, row.id, streamId);
|
|
209
|
+
if (streamId)
|
|
210
|
+
lastStreamId = streamId;
|
|
211
|
+
dispatched += 1;
|
|
212
|
+
this._lastAppliedAtMs = Date.now();
|
|
213
|
+
}
|
|
214
|
+
catch (err) {
|
|
215
|
+
if (err instanceof FenceLostError ||
|
|
216
|
+
err instanceof FenceCheckUnavailableError) {
|
|
217
|
+
// The lease was lost/taken-over (FenceLostError) OR the fence-check
|
|
218
|
+
// READ failed transiently (FenceCheckUnavailableError — lease-redis
|
|
219
|
+
// blip). Either way ABORT the rest of the batch WITHOUT recordFailure:
|
|
220
|
+
// a transient lease-redis blip is NOT a publish failure, so it must
|
|
221
|
+
// NOT bump publish_attempts (5 blips would otherwise silently abandon
|
|
222
|
+
// a row whose every publish succeeded). The row is retried on lease
|
|
223
|
+
// recovery; the tx commits only the rows marked BEFORE the loss (each
|
|
224
|
+
// fence-validated). Mirrors Streams/Replication + the Go dispatcher.
|
|
225
|
+
this.hooks.leaseLost();
|
|
226
|
+
fenceLost = true;
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
// D401: a publish failure NEVER deletes / DLQs the row — record the
|
|
230
|
+
// failure (bump attempts) + leave it. The 24h-unpublished sweep
|
|
231
|
+
// surfaces persistent liveness problems.
|
|
232
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
233
|
+
if (this.recordFailure) {
|
|
234
|
+
await this.recordFailure(tx, row.id, msg);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
finally {
|
|
239
|
+
this._inFlight -= 1;
|
|
240
|
+
}
|
|
241
|
+
if (fenceLost)
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
// Advance the HWM cursor in the SAME tx as the marks (atomic): the cursor
|
|
245
|
+
// can never advance past a row that wasn't actually marked dispatched.
|
|
246
|
+
if (lastStreamId !== null) {
|
|
247
|
+
await this.checkpoint.advance({ subscription: this.subscription, lastStreamId }, tx);
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
if (lastStreamId !== null) {
|
|
251
|
+
this._hwm = { lastStreamId };
|
|
252
|
+
this.hooks.recordHwm(hwmGaugeValue(lastStreamId));
|
|
253
|
+
}
|
|
254
|
+
this.hooks.recordDepth(dispatched);
|
|
255
|
+
return dispatched;
|
|
256
|
+
}
|
|
257
|
+
/** Run exactly one drain pass (test seam / cron tick). */
|
|
258
|
+
async runOnce() {
|
|
259
|
+
return this.drainOnce();
|
|
260
|
+
}
|
|
261
|
+
async stop(opts) {
|
|
262
|
+
const timeoutMs = opts?.timeoutMs ?? DEFAULT_STOP_TIMEOUT_MS;
|
|
263
|
+
const start = Date.now();
|
|
264
|
+
this._stopped = true;
|
|
265
|
+
this._running = false;
|
|
266
|
+
try {
|
|
267
|
+
await Promise.race([
|
|
268
|
+
this.loop,
|
|
269
|
+
new Promise((r) => setTimeout(r, timeoutMs)),
|
|
270
|
+
]);
|
|
271
|
+
}
|
|
272
|
+
catch {
|
|
273
|
+
/* swallow */
|
|
274
|
+
}
|
|
275
|
+
while (this._inFlight > 0 && Date.now() - start < timeoutMs) {
|
|
276
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
277
|
+
}
|
|
278
|
+
const drainedCleanly = this._inFlight === 0;
|
|
279
|
+
await this.lease.release();
|
|
280
|
+
const durationMs = Date.now() - start;
|
|
281
|
+
this.hooks.recordDrainDuration(durationMs);
|
|
282
|
+
return { drainedCleanly, durationMs };
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
//# sourceMappingURL=outbox-dispatcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbox-dispatcher.js","sourceRoot":"","sources":["../../src/worker/outbox-dispatcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import type { CheckpointStore } from "./checkpoint-store.js";
|
|
2
|
+
import type { DeadLetterSink } from "./dead-letter.js";
|
|
3
|
+
import type { DedupeStore } from "./dedupe-store.js";
|
|
4
|
+
import { ObservabilityHooks } from "./observability-hooks.js";
|
|
5
|
+
import { type SingleActiveLeaseOpts } from "./single-active-lease.js";
|
|
6
|
+
import { type StreamsRedisLike } from "./streams-worker.js";
|
|
7
|
+
import type { SqlExecutor } from "./tx.js";
|
|
8
|
+
import type { WorkerHandle, WorkerHwm, WorkerStopOptions, WorkerStopResult } from "./worker-handle.js";
|
|
9
|
+
/** A replication event off the source stream. Carries the LWW version. */
|
|
10
|
+
export interface ReplicationEvent {
|
|
11
|
+
/** Dedupe id — `(event_id, topic)` is the composite dedupe key (D198). */
|
|
12
|
+
event_id: string;
|
|
13
|
+
/** The outbox topic. */
|
|
14
|
+
topic: string;
|
|
15
|
+
/** The replicated entity's id (the projection key). */
|
|
16
|
+
entity_id: string;
|
|
17
|
+
/** The monotonic source version — drives last-write-wins. */
|
|
18
|
+
entity_version: number | string | bigint;
|
|
19
|
+
/** Optional source emission ms for lag. */
|
|
20
|
+
occurred_at_ms?: number;
|
|
21
|
+
/** The rest of the payload (the projection input). */
|
|
22
|
+
[key: string]: unknown;
|
|
23
|
+
}
|
|
24
|
+
/** The apply context handed to the injected projection upsert INSIDE the tx. */
|
|
25
|
+
export interface ReplicationApplyContext {
|
|
26
|
+
tx: SqlExecutor;
|
|
27
|
+
event: ReplicationEvent;
|
|
28
|
+
streamId: string;
|
|
29
|
+
/** THE fence guard — call BEFORE the projection upsert. */
|
|
30
|
+
validateFence(): Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
/** The injected projection upsert. Runs inside the worker's apply tx. */
|
|
33
|
+
export type ReplicationApplyHandler = (ctx: ReplicationApplyContext) => Promise<void>;
|
|
34
|
+
/** The injected audit emitter — fires AFTER a successful commit (§ 4 audit). */
|
|
35
|
+
export type ReplicationAuditHook = (info: {
|
|
36
|
+
event: ReplicationEvent;
|
|
37
|
+
streamId: string;
|
|
38
|
+
/** True when the event applied; false when LWW-skipped (still consumed). */
|
|
39
|
+
applied: boolean;
|
|
40
|
+
}) => Promise<void> | void;
|
|
41
|
+
/** A snapshot bootstrap source — streams the snapshot rows + the HWM to stitch. */
|
|
42
|
+
export interface SnapshotBootstrap {
|
|
43
|
+
/**
|
|
44
|
+
* Apply the full snapshot into the projection and return the high-water
|
|
45
|
+
* stream id the live consume must stitch from. The worker writes this as the
|
|
46
|
+
* cursor so live consume resumes exactly there (§ 7 stitch). The bootstrap
|
|
47
|
+
* runs its own apply (it owns the projection schema); the worker only records
|
|
48
|
+
* the returned HWM as the durable cursor.
|
|
49
|
+
*/
|
|
50
|
+
bootstrap(tx: SqlExecutor): Promise<{
|
|
51
|
+
highWaterStreamId: string;
|
|
52
|
+
}>;
|
|
53
|
+
}
|
|
54
|
+
export interface ReplicationWorkerOpts {
|
|
55
|
+
redis: StreamsRedisLike;
|
|
56
|
+
/** The source replication stream key. */
|
|
57
|
+
sourceStream: string;
|
|
58
|
+
/** The injected projection upsert. */
|
|
59
|
+
apply: ReplicationApplyHandler;
|
|
60
|
+
/**
|
|
61
|
+
* Reads the projection's CURRENT source_entity_version for an entity, for the
|
|
62
|
+
* LWW comparison. Returns null when the entity isn't projected yet (→ apply).
|
|
63
|
+
*/
|
|
64
|
+
currentVersion: (tx: SqlExecutor, event: ReplicationEvent) => Promise<bigint | null>;
|
|
65
|
+
/** Opens an apply transaction; the worker runs dedupe/checkpoint/apply on it. */
|
|
66
|
+
begin: <T>(fn: (tx: SqlExecutor) => Promise<T>) => Promise<T>;
|
|
67
|
+
dedupe: DedupeStore;
|
|
68
|
+
checkpoint: CheckpointStore;
|
|
69
|
+
lease: Omit<SingleActiveLeaseOpts, "onLeaseLost">;
|
|
70
|
+
/** Checkpoint subscription key. Default `replication:<sourceStream>`. */
|
|
71
|
+
subscription?: string;
|
|
72
|
+
deadLetter: DeadLetterSink;
|
|
73
|
+
/** Optional snapshot bootstrap (run once if the cursor is absent). */
|
|
74
|
+
snapshot?: SnapshotBootstrap;
|
|
75
|
+
/** Optional audit hook (fires after each successful commit). */
|
|
76
|
+
audit?: ReplicationAuditHook;
|
|
77
|
+
retryMaxAttempts?: number;
|
|
78
|
+
pollBatch?: number;
|
|
79
|
+
blockMs?: number;
|
|
80
|
+
/** XAUTOCLAIM crash-recovery threshold (ms). Default max(lease ttlMs, 30_000). */
|
|
81
|
+
reclaimMinIdleMs?: number;
|
|
82
|
+
hooks?: ObservabilityHooks;
|
|
83
|
+
workerLabel?: string;
|
|
84
|
+
/** Launch the background consume loop on `start()`. Default true; tests pass
|
|
85
|
+
* false to drive `runOnce()` deterministically. */
|
|
86
|
+
autoStart?: boolean;
|
|
87
|
+
}
|
|
88
|
+
/** Consumer-group name — `${service}:${stream}` (canonical per replica-consumer). */
|
|
89
|
+
export declare function replicationConsumerGroup(service: string, stream: string): string;
|
|
90
|
+
/**
|
|
91
|
+
* ReplicationWorker — the Pattern-3 subscriber. Composes lease + dedupe +
|
|
92
|
+
* checkpoint + hooks + drain + snapshot-bootstrap + LWW + audit. EXACTLY-ONCE
|
|
93
|
+
* apply, monotonic projection (no LWW regression), atomic cursor+dedupe+upsert.
|
|
94
|
+
*/
|
|
95
|
+
export declare class ReplicationWorker implements WorkerHandle {
|
|
96
|
+
private readonly redis;
|
|
97
|
+
private readonly sourceStream;
|
|
98
|
+
private readonly applyHandler;
|
|
99
|
+
private readonly currentVersion;
|
|
100
|
+
private readonly begin;
|
|
101
|
+
private readonly dedupe;
|
|
102
|
+
private readonly checkpoint;
|
|
103
|
+
private readonly lease;
|
|
104
|
+
private readonly subscription;
|
|
105
|
+
private readonly deadLetter;
|
|
106
|
+
private readonly snapshot?;
|
|
107
|
+
private readonly audit?;
|
|
108
|
+
private readonly retryMaxAttempts;
|
|
109
|
+
private readonly pollBatch;
|
|
110
|
+
private readonly blockMs;
|
|
111
|
+
private readonly reclaimMinIdleMs;
|
|
112
|
+
private readonly hooks;
|
|
113
|
+
private readonly autoStart;
|
|
114
|
+
private readonly group;
|
|
115
|
+
private readonly consumer;
|
|
116
|
+
private readonly retries;
|
|
117
|
+
private _running;
|
|
118
|
+
private _stopped;
|
|
119
|
+
private _inFlight;
|
|
120
|
+
private _bootstrapped;
|
|
121
|
+
private _hwm;
|
|
122
|
+
private _lastAppliedAtMs;
|
|
123
|
+
private groupEnsured;
|
|
124
|
+
private loop;
|
|
125
|
+
constructor(opts: ReplicationWorkerOpts);
|
|
126
|
+
get running(): boolean;
|
|
127
|
+
get leaseAcquired(): boolean;
|
|
128
|
+
get lag(): number | null;
|
|
129
|
+
get currentHwm(): WorkerHwm;
|
|
130
|
+
/** True once the snapshot bootstrap (if any) has run / been determined absent. */
|
|
131
|
+
get bootstrapped(): boolean;
|
|
132
|
+
private ensureGroup;
|
|
133
|
+
start(): Promise<void>;
|
|
134
|
+
/**
|
|
135
|
+
* Snapshot-bootstrap + HWM stitch (§ 7): if the durable cursor is ABSENT (cold
|
|
136
|
+
* start) AND a snapshot source is wired, run the snapshot bootstrap inside ONE
|
|
137
|
+
* tx and write the returned high-water stream id as the cursor — live consume
|
|
138
|
+
* then resumes EXACTLY from there (no gap, no double-apply of the snapshot
|
|
139
|
+
* window). If a cursor already exists we skip the snapshot and resume live.
|
|
140
|
+
*/
|
|
141
|
+
maybeBootstrap(): Promise<void>;
|
|
142
|
+
private runLoop;
|
|
143
|
+
private pollOnce;
|
|
144
|
+
/**
|
|
145
|
+
* Dead-letter + XACK every structurally-unparseable (malformed-JSON) entry. A
|
|
146
|
+
* malformed entry is a POISON message (no decodable event) — leaving it in the
|
|
147
|
+
* PEL only re-cycles it through XAUTOCLAIM forever. Route the raw bytes through
|
|
148
|
+
* the (PII-redacting) dead-letter sink, then XACK so it leaves the PEL. If the
|
|
149
|
+
* sink fails, leave the entry in the PEL (recoverable; never silently dropped).
|
|
150
|
+
*/
|
|
151
|
+
private handleMalformedEntries;
|
|
152
|
+
/**
|
|
153
|
+
* Apply one replication event: dedupe-skip → LWW check → apply tx (projection
|
|
154
|
+
* + dedupe.record + checkpoint.advance, fence-guarded, ONE tx) → XACK → audit.
|
|
155
|
+
*/
|
|
156
|
+
private applyOne;
|
|
157
|
+
/**
|
|
158
|
+
* XACK an already-committed entry, SWALLOWING a transient ack failure. The
|
|
159
|
+
* XACK is post-commit (or post-dedupe-skip) and NOT part of the apply tx — a
|
|
160
|
+
* failing XACK is a transient redis blip, never a poison event. On failure the
|
|
161
|
+
* entry stays un-acked in the PEL and is re-acked next poll once redis
|
|
162
|
+
* recovers (the durable dedupe row makes the redelivery a no-op). Matches Go's
|
|
163
|
+
* `_, _ = Ack(...)`; a throw here must NEVER reach retry/DLQ.
|
|
164
|
+
*/
|
|
165
|
+
private ackSwallow;
|
|
166
|
+
private retryOrDeadLetter;
|
|
167
|
+
runOnce(): Promise<number>;
|
|
168
|
+
stop(opts?: WorkerStopOptions): Promise<WorkerStopResult>;
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=replication-worker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replication-worker.d.ts","sourceRoot":"","sources":["../../src/worker/replication-worker.ts"],"names":[],"mappings":"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"}
|