@arki/journal 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +541 -2
- package/dist/api.d.ts +336 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +2 -0
- package/dist/api.js.map +1 -0
- package/dist/command.d.ts +27 -0
- package/dist/command.d.ts.map +1 -0
- package/dist/command.js +157 -0
- package/dist/command.js.map +1 -0
- package/dist/debug.d.ts +7 -0
- package/dist/debug.d.ts.map +1 -0
- package/dist/debug.js +8 -0
- package/dist/debug.js.map +1 -0
- package/dist/dot.d.ts +102 -0
- package/dist/dot.d.ts.map +1 -0
- package/dist/dot.js +159 -0
- package/dist/dot.js.map +1 -0
- package/dist/entity.d.ts +56 -0
- package/dist/entity.d.ts.map +1 -0
- package/dist/entity.js +174 -0
- package/dist/entity.js.map +1 -0
- package/dist/errors.d.ts +47 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +112 -0
- package/dist/errors.js.map +1 -0
- package/dist/event.d.ts +9 -0
- package/dist/event.d.ts.map +1 -0
- package/dist/event.js +19 -0
- package/dist/event.js.map +1 -0
- package/dist/fold.d.ts +29 -0
- package/dist/fold.d.ts.map +1 -0
- package/dist/fold.js +49 -0
- package/dist/fold.js.map +1 -0
- package/dist/handlers.d.ts +26 -0
- package/dist/handlers.d.ts.map +1 -0
- package/dist/handlers.js +130 -0
- package/dist/handlers.js.map +1 -0
- package/dist/history.d.ts +49 -0
- package/dist/history.d.ts.map +1 -0
- package/dist/history.js +259 -0
- package/dist/history.js.map +1 -0
- package/dist/hooks.d.ts +14 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +67 -0
- package/dist/hooks.js.map +1 -0
- package/dist/id.d.ts +18 -0
- package/dist/id.d.ts.map +1 -0
- package/dist/id.js +41 -0
- package/dist/id.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/journal.d.ts +51 -0
- package/dist/journal.d.ts.map +1 -0
- package/dist/journal.js +181 -0
- package/dist/journal.js.map +1 -0
- package/dist/listen.d.ts +37 -0
- package/dist/listen.d.ts.map +1 -0
- package/dist/listen.js +90 -0
- package/dist/listen.js.map +1 -0
- package/dist/orpc.d.ts +21 -0
- package/dist/orpc.d.ts.map +1 -0
- package/dist/orpc.js +57 -0
- package/dist/orpc.js.map +1 -0
- package/dist/pg.d.ts +537 -0
- package/dist/pg.d.ts.map +1 -0
- package/dist/pg.js +80 -0
- package/dist/pg.js.map +1 -0
- package/dist/storage.d.ts +52 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +221 -0
- package/dist/storage.js.map +1 -0
- package/dist/testing.d.ts +19 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +23 -0
- package/dist/testing.js.map +1 -0
- package/dist/transaction-guard.d.ts +2 -0
- package/dist/transaction-guard.d.ts.map +1 -0
- package/dist/transaction-guard.js +39 -0
- package/dist/transaction-guard.js.map +1 -0
- package/dist/types.d.ts +414 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/worker.d.ts +109 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +459 -0
- package/dist/worker.js.map +1 -0
- package/dist/write.d.ts +39 -0
- package/dist/write.d.ts.map +1 -0
- package/dist/write.js +287 -0
- package/dist/write.js.map +1 -0
- package/docs/agent-guide.md +324 -0
- package/llms.txt +40 -0
- package/package.json +99 -4
- package/src/api.ts +465 -0
- package/src/command.ts +242 -0
- package/src/debug.ts +8 -0
- package/src/dot.ts +296 -0
- package/src/entity.ts +377 -0
- package/src/errors.ts +134 -0
- package/src/event.ts +26 -0
- package/src/fold.ts +97 -0
- package/src/handlers.ts +262 -0
- package/src/history.ts +390 -0
- package/src/hooks.ts +85 -0
- package/src/id.ts +54 -0
- package/src/index.ts +76 -0
- package/src/journal.ts +256 -0
- package/src/listen.ts +109 -0
- package/src/orpc.ts +59 -0
- package/src/pg.ts +107 -0
- package/src/storage.ts +277 -0
- package/src/test-support.ts +82 -0
- package/src/testing.ts +23 -0
- package/src/transaction-guard.ts +41 -0
- package/src/types.ts +439 -0
- package/src/worker.ts +610 -0
- package/src/write.ts +434 -0
package/dist/worker.js
ADDED
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
import { and, asc, desc, eq, gt, gte, inArray, isNotNull, isNull, lte, max, notInArray, or, sql } from 'drizzle-orm';
|
|
2
|
+
import { debugDrain, debugWorker } from './debug.js';
|
|
3
|
+
import { JournalError } from './errors.js';
|
|
4
|
+
import { findEventDefinition } from './fold.js';
|
|
5
|
+
import { leaseToken } from './id.js';
|
|
6
|
+
import { assertRootDb } from './storage.js';
|
|
7
|
+
const DEFAULT_LEASE_SECONDS = 60;
|
|
8
|
+
const MAX_ATTEMPTS = 8;
|
|
9
|
+
const BACKOFF_BASE_MS = 1000;
|
|
10
|
+
const BACKOFF_CAP_MS = 300_000;
|
|
11
|
+
const DEFAULT_POLL_MS = 1000;
|
|
12
|
+
function errorText(error) {
|
|
13
|
+
return error instanceof Error ? `${error.name}: ${error.message}` : String(error);
|
|
14
|
+
}
|
|
15
|
+
/** Seconds to wait before the next attempt: doubling with jitter, capped at 5 minutes. */
|
|
16
|
+
function backoffSeconds(attempts) {
|
|
17
|
+
const base = Math.min(BACKOFF_CAP_MS, BACKOFF_BASE_MS * 2 ** Math.max(0, attempts - 1));
|
|
18
|
+
const jitter = base * (Math.random() * 0.5 - 0.25);
|
|
19
|
+
return Math.round(Math.min(BACKOFF_CAP_MS, base + jitter)) / 1000;
|
|
20
|
+
}
|
|
21
|
+
/** Database time plus `seconds`. The worker's clock never decides a lease or a retry. */
|
|
22
|
+
const dbNowPlus = (seconds) => sql `now() + make_interval(secs => ${seconds})`;
|
|
23
|
+
export function createDrain(deps) {
|
|
24
|
+
const { events: eventsTable, jobs: jobsTable } = deps.tables;
|
|
25
|
+
const { decodeStoredEvent } = deps.history;
|
|
26
|
+
const effectsByName = new Map(deps.effects.map(effect => [effect.name, effect]));
|
|
27
|
+
const known = [...effectsByName.keys()];
|
|
28
|
+
// Every time here is database time, so a worker with a skewed clock
|
|
29
|
+
// cannot take a live lease or push a retry into the far future.
|
|
30
|
+
const claimOne = (db, leaseSeconds) => db.transaction(async (tx) => {
|
|
31
|
+
const due = await tx
|
|
32
|
+
.select({ id: jobsTable.id })
|
|
33
|
+
.from(jobsTable)
|
|
34
|
+
.where(and(isNull(jobsTable.deadAt), lte(jobsTable.availableAt, sql `now()`), or(isNull(jobsTable.leaseUntil), lte(jobsTable.leaseUntil, sql `now()`)), inArray(jobsTable.effect, known)))
|
|
35
|
+
.orderBy(desc(jobsTable.priority), asc(jobsTable.availableAt))
|
|
36
|
+
.limit(1)
|
|
37
|
+
.for('update', { skipLocked: true });
|
|
38
|
+
const first = due[0];
|
|
39
|
+
if (first === undefined)
|
|
40
|
+
return;
|
|
41
|
+
const [claimed] = await tx
|
|
42
|
+
.update(jobsTable)
|
|
43
|
+
.set({
|
|
44
|
+
leaseToken: leaseToken(),
|
|
45
|
+
leaseUntil: dbNowPlus(leaseSeconds),
|
|
46
|
+
attempts: sql `${jobsTable.attempts} + 1`,
|
|
47
|
+
})
|
|
48
|
+
.where(eq(jobsTable.id, first.id))
|
|
49
|
+
.returning();
|
|
50
|
+
return claimed;
|
|
51
|
+
});
|
|
52
|
+
/**
|
|
53
|
+
* Keeps the lease alive while the effect runs: every half lease, push `lease_until`
|
|
54
|
+
* out by a full lease, under this worker's token. Zero rows means the lease was
|
|
55
|
+
* lost (the worker stalled past the lease and another one reclaimed the job):
|
|
56
|
+
* the effect's signal aborts so it can stop, and its ack will find nothing to
|
|
57
|
+
* acknowledge. The timer never keeps the process alive.
|
|
58
|
+
*/
|
|
59
|
+
const renewWhile = (db, job, leaseSeconds, lost) => {
|
|
60
|
+
const token = job.leaseToken ?? '';
|
|
61
|
+
let inFlight = false;
|
|
62
|
+
let finished = false;
|
|
63
|
+
const timer = setInterval(() => {
|
|
64
|
+
if (inFlight)
|
|
65
|
+
return;
|
|
66
|
+
inFlight = true;
|
|
67
|
+
void db
|
|
68
|
+
.update(jobsTable)
|
|
69
|
+
.set({ leaseUntil: dbNowPlus(leaseSeconds) })
|
|
70
|
+
.where(and(eq(jobsTable.id, job.id), eq(jobsTable.leaseToken, token)))
|
|
71
|
+
.returning({ id: jobsTable.id })
|
|
72
|
+
.then(rows => {
|
|
73
|
+
if (rows.length === 0 && !finished) {
|
|
74
|
+
clearInterval(timer);
|
|
75
|
+
lost.abort(new Error(`journal: the lease on job ${job.id} was lost; another worker holds it now`));
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
.catch((error) => debugDrain.debug('{effect} {jobId}: lease renewal failed: {failed}', {
|
|
79
|
+
effect: job.effect,
|
|
80
|
+
jobId: job.id,
|
|
81
|
+
failed: errorText(error),
|
|
82
|
+
}))
|
|
83
|
+
.finally(() => {
|
|
84
|
+
inFlight = false;
|
|
85
|
+
});
|
|
86
|
+
}, leaseSeconds * 500);
|
|
87
|
+
// Node and Bun return a handle with unref(); browsers and Deno return a number.
|
|
88
|
+
const handle = timer;
|
|
89
|
+
if (typeof handle === 'object' && handle !== null && 'unref' in handle && typeof handle.unref === 'function') {
|
|
90
|
+
handle.unref();
|
|
91
|
+
}
|
|
92
|
+
return () => {
|
|
93
|
+
finished = true;
|
|
94
|
+
clearInterval(timer);
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
const runJob = async (db, job, signal, leaseSeconds) => {
|
|
98
|
+
const effect = effectsByName.get(job.effect);
|
|
99
|
+
const lost = new AbortController();
|
|
100
|
+
const stopRenewing = renewWhile(db, job, leaseSeconds, lost);
|
|
101
|
+
try {
|
|
102
|
+
if (effect === undefined)
|
|
103
|
+
throw new Error(`effect "${job.effect}" is not registered`);
|
|
104
|
+
const [eventRow] = await db.select().from(eventsTable).where(eq(eventsTable.seq, job.eventSeq));
|
|
105
|
+
if (eventRow === undefined)
|
|
106
|
+
throw new Error(`event seq ${job.eventSeq} not found`);
|
|
107
|
+
const event = decodeStoredEvent(eventRow, findEventDefinition(effect.entities, eventRow.kind, eventRow.type), eventRow.entityId);
|
|
108
|
+
// Inside the lease: a hook that throws fails the job like a handler failure.
|
|
109
|
+
const ownSignal = AbortSignal.any([signal, lost.signal]);
|
|
110
|
+
await deps.hooks.run({ name: job.effect, event, jobId: job.id, attempt: job.attempts }, () => effect.run(event, { jobId: job.id, signal: ownSignal, db, run: deps.runOn(db, event) }));
|
|
111
|
+
await db.delete(jobsTable).where(and(eq(jobsTable.id, job.id), eq(jobsTable.leaseToken, job.leaseToken ?? '')));
|
|
112
|
+
debugDrain.debug('{effect} {jobId}: done', { effect: job.effect, jobId: job.id });
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
const dead = job.attempts >= MAX_ATTEMPTS;
|
|
116
|
+
await db
|
|
117
|
+
.update(jobsTable)
|
|
118
|
+
.set({
|
|
119
|
+
lastError: errorText(error),
|
|
120
|
+
leaseToken: null,
|
|
121
|
+
leaseUntil: null,
|
|
122
|
+
...(dead ? { deadAt: sql `now()` } : { availableAt: dbNowPlus(backoffSeconds(job.attempts)) }),
|
|
123
|
+
})
|
|
124
|
+
.where(and(eq(jobsTable.id, job.id), eq(jobsTable.leaseToken, job.leaseToken ?? '')));
|
|
125
|
+
debugDrain.debug('{effect} {jobId}: attempt {attempts} failed{value4}: {value5}', {
|
|
126
|
+
effect: job.effect,
|
|
127
|
+
jobId: job.id,
|
|
128
|
+
attempts: job.attempts,
|
|
129
|
+
value4: dead ? ', dead' : '',
|
|
130
|
+
value5: errorText(error),
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
finally {
|
|
134
|
+
stopRenewing();
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
return async (db, opts) => {
|
|
138
|
+
assertRootDb(db, 'drain');
|
|
139
|
+
deps.hooks.freeze();
|
|
140
|
+
const batchSize = opts?.batchSize ?? 20;
|
|
141
|
+
const leaseSeconds = opts?.leaseSeconds ?? DEFAULT_LEASE_SECONDS;
|
|
142
|
+
const signal = opts?.signal ?? new AbortController().signal;
|
|
143
|
+
if (known.length === 0)
|
|
144
|
+
return 0;
|
|
145
|
+
// One job is claimed at a time, right before it runs, so its lease starts
|
|
146
|
+
// when its work starts. Claiming the whole batch up front would start every
|
|
147
|
+
// lease at once: while the first jobs ran, the leases of the last ones
|
|
148
|
+
// could run out, and another worker would take them and run them twice.
|
|
149
|
+
// An aborted signal stops the claiming; the job already running finishes.
|
|
150
|
+
let claimed = 0;
|
|
151
|
+
while (claimed < batchSize && !signal.aborted) {
|
|
152
|
+
const job = await claimOne(db, leaseSeconds);
|
|
153
|
+
if (job === undefined)
|
|
154
|
+
break;
|
|
155
|
+
claimed += 1;
|
|
156
|
+
await runJob(db, job, signal, leaseSeconds);
|
|
157
|
+
}
|
|
158
|
+
return claimed;
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Counts pending jobs whose effect this journal does not have. `drain` never
|
|
163
|
+
* claims them, on purpose: during a rolling deploy an older worker may still
|
|
164
|
+
* have that effect. But once every worker runs the new code, a renamed or
|
|
165
|
+
* removed effect leaves its jobs here for good, so they must be visible.
|
|
166
|
+
*/
|
|
167
|
+
export function createStrandedJobs(deps) {
|
|
168
|
+
const { jobs: jobsTable } = deps.tables;
|
|
169
|
+
return async (db) => db
|
|
170
|
+
.select({ effect: jobsTable.effect, jobs: sql `count(*)::int` })
|
|
171
|
+
.from(jobsTable)
|
|
172
|
+
.where(and(isNull(jobsTable.deadAt), deps.effectNames.length > 0 ? notInArray(jobsTable.effect, [...deps.effectNames]) : undefined))
|
|
173
|
+
.groupBy(jobsTable.effect)
|
|
174
|
+
.orderBy(asc(jobsTable.effect));
|
|
175
|
+
}
|
|
176
|
+
/** The job verbs an operator uses: list, retry a dead job, discard a dead job. */
|
|
177
|
+
export function createAdmin(deps) {
|
|
178
|
+
const { jobs: jobsTable } = deps.tables;
|
|
179
|
+
const jobs = (db, opts) => {
|
|
180
|
+
const status = opts?.status ?? 'pending';
|
|
181
|
+
return db
|
|
182
|
+
.select()
|
|
183
|
+
.from(jobsTable)
|
|
184
|
+
.where(and(status === 'pending' ? isNull(jobsTable.deadAt) : status === 'dead' ? isNotNull(jobsTable.deadAt) : undefined, opts?.effect === undefined ? undefined : eq(jobsTable.effect, opts.effect)))
|
|
185
|
+
.orderBy(asc(jobsTable.availableAt))
|
|
186
|
+
.limit(opts?.limit ?? 100);
|
|
187
|
+
};
|
|
188
|
+
/** Dead to pending, in one statement: attempts and lease cleared, due now. Wakes the workers. */
|
|
189
|
+
const retry = async (db, jobId) => {
|
|
190
|
+
const rows = await db
|
|
191
|
+
.update(jobsTable)
|
|
192
|
+
.set({ deadAt: null, attempts: 0, lastError: null, leaseToken: null, leaseUntil: null, availableAt: sql `now()` })
|
|
193
|
+
.where(and(eq(jobsTable.id, jobId), isNotNull(jobsTable.deadAt)))
|
|
194
|
+
.returning({ id: jobsTable.id });
|
|
195
|
+
if (rows.length === 0)
|
|
196
|
+
throw new Error(`journal: job ${JSON.stringify(jobId)} is not a dead job; only a dead job is retried`);
|
|
197
|
+
deps.wake();
|
|
198
|
+
};
|
|
199
|
+
/** Delete a dead job. A live one is never deleted here: that would not stop its work, only lose the record of it. */
|
|
200
|
+
const discard = async (db, jobId) => {
|
|
201
|
+
const rows = await db
|
|
202
|
+
.delete(jobsTable)
|
|
203
|
+
.where(and(eq(jobsTable.id, jobId), isNotNull(jobsTable.deadAt)))
|
|
204
|
+
.returning({ id: jobsTable.id });
|
|
205
|
+
if (rows.length === 0)
|
|
206
|
+
throw new Error(`journal: job ${JSON.stringify(jobId)} is not a dead job; only a dead job is discarded`);
|
|
207
|
+
};
|
|
208
|
+
return { jobs, retry, discard };
|
|
209
|
+
}
|
|
210
|
+
const DEFAULT_CATCH_UP_BATCH = 100;
|
|
211
|
+
export function createCatchUp(deps) {
|
|
212
|
+
const { events: eventsTable, cursors: cursorsTable } = deps.tables;
|
|
213
|
+
const { decodeStoredEvent } = deps.history;
|
|
214
|
+
const byName = new Map(deps.projections.map(projection => [projection.name, projection]));
|
|
215
|
+
/** The cursor row, created at 0 if missing, locked for this transaction. */
|
|
216
|
+
const lockCursor = async (tx, name) => {
|
|
217
|
+
await tx.insert(cursorsTable).values({ name, seq: 0 }).onConflictDoNothing();
|
|
218
|
+
const [row] = await tx
|
|
219
|
+
.select({ seq: cursorsTable.seq })
|
|
220
|
+
.from(cursorsTable)
|
|
221
|
+
.where(eq(cursorsTable.name, name))
|
|
222
|
+
.for('update');
|
|
223
|
+
if (row === undefined)
|
|
224
|
+
throw new Error(`journal: cursor "${name}" vanished while locked`);
|
|
225
|
+
return row.seq;
|
|
226
|
+
};
|
|
227
|
+
/**
|
|
228
|
+
* One batch for one projection: lock its cursor, scan the next events in seq order,
|
|
229
|
+
* apply the matching ones, move the cursor to the last event scanned, commit. The
|
|
230
|
+
* cursor is global scan progress, so lag reaches zero and two workers cannot apply
|
|
231
|
+
* one batch twice: the second waits on the row lock and starts after the first moved it.
|
|
232
|
+
*/
|
|
233
|
+
const batchFor = async (db, projection, batchSize) => db.transaction(async (tx) => {
|
|
234
|
+
const from = await lockCursor(tx, projection.name);
|
|
235
|
+
const rows = await tx
|
|
236
|
+
.select()
|
|
237
|
+
.from(eventsTable)
|
|
238
|
+
.where(gt(eventsTable.seq, from))
|
|
239
|
+
.orderBy(asc(eventsTable.seq))
|
|
240
|
+
.limit(batchSize);
|
|
241
|
+
const last = rows.at(-1);
|
|
242
|
+
if (last === undefined)
|
|
243
|
+
return 0;
|
|
244
|
+
const kinds = new Set(projection.entities.map(entity => entity.kind));
|
|
245
|
+
for (const row of rows) {
|
|
246
|
+
if (!kinds.has(row.kind) || !projection.types.has(row.type))
|
|
247
|
+
continue;
|
|
248
|
+
await projection.run(tx, decodeStoredEvent(row, findEventDefinition(projection.entities, row.kind, row.type), row.entityId));
|
|
249
|
+
}
|
|
250
|
+
await tx
|
|
251
|
+
.update(cursorsTable)
|
|
252
|
+
.set({ seq: last.seq, updatedAt: sql `now()` })
|
|
253
|
+
.where(eq(cursorsTable.name, projection.name));
|
|
254
|
+
return rows.length;
|
|
255
|
+
});
|
|
256
|
+
const catchUp = async (db, opts) => {
|
|
257
|
+
assertRootDb(db, 'catchUp');
|
|
258
|
+
const batchSize = opts?.batchSize ?? DEFAULT_CATCH_UP_BATCH;
|
|
259
|
+
let scanned = 0;
|
|
260
|
+
for (const projection of deps.projections) {
|
|
261
|
+
// One projection's failure leaves the others running; its batch rolled back and runs again next pass.
|
|
262
|
+
try {
|
|
263
|
+
scanned += await batchFor(db, projection, batchSize);
|
|
264
|
+
}
|
|
265
|
+
catch (error) {
|
|
266
|
+
debugDrain.debug('projection {projectionName}: batch failed: {failed}', {
|
|
267
|
+
projectionName: projection.name,
|
|
268
|
+
failed: errorText(error),
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
return { scanned };
|
|
273
|
+
};
|
|
274
|
+
const reset = async (db, projection, clear) => {
|
|
275
|
+
assertRootDb(db, 'reset');
|
|
276
|
+
if (!byName.has(projection.name))
|
|
277
|
+
throw new JournalError('BAD_DEFINITION', 'projection', projection.name, `journal: "${projection.name}" is not an async projection of this journal`);
|
|
278
|
+
await db.transaction(async (tx) => {
|
|
279
|
+
// The lock first, so no batch lands between the clearing and the rewind.
|
|
280
|
+
await lockCursor(tx, projection.name);
|
|
281
|
+
await clear?.(tx);
|
|
282
|
+
await tx
|
|
283
|
+
.update(cursorsTable)
|
|
284
|
+
.set({ seq: 0, updatedAt: sql `now()` })
|
|
285
|
+
.where(eq(cursorsTable.name, projection.name));
|
|
286
|
+
});
|
|
287
|
+
};
|
|
288
|
+
const cursors = async (db) => {
|
|
289
|
+
const [top] = await db.select({ seq: max(eventsTable.seq) }).from(eventsTable);
|
|
290
|
+
const latest = top?.seq ?? 0;
|
|
291
|
+
const rows = await db.select().from(cursorsTable);
|
|
292
|
+
const stored = new Map(rows.map(row => [row.name, row.seq]));
|
|
293
|
+
return deps.projections.map(projection => {
|
|
294
|
+
const seq = stored.get(projection.name) ?? 0;
|
|
295
|
+
return { name: projection.name, seq, lag: Math.max(0, latest - seq) };
|
|
296
|
+
});
|
|
297
|
+
};
|
|
298
|
+
return { catchUp, reset, cursors };
|
|
299
|
+
}
|
|
300
|
+
/** A wake payload: the seq range one commit recorded. Anything else is ignored. */
|
|
301
|
+
const parseRange = (payload) => {
|
|
302
|
+
try {
|
|
303
|
+
const parsed = JSON.parse(payload);
|
|
304
|
+
if (typeof parsed !== 'object' || parsed === null || !('from' in parsed) || !('to' in parsed))
|
|
305
|
+
return undefined;
|
|
306
|
+
const { from, to } = parsed;
|
|
307
|
+
if (typeof from !== 'number' || typeof to !== 'number' || !Number.isInteger(from) || !Number.isInteger(to))
|
|
308
|
+
return undefined;
|
|
309
|
+
return from <= to ? { from, to } : undefined;
|
|
310
|
+
}
|
|
311
|
+
catch {
|
|
312
|
+
return undefined;
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
export function createTapDispatch(deps) {
|
|
316
|
+
const eventsTable = deps.tables.events;
|
|
317
|
+
const kinds = [...new Set(deps.taps.flatMap(tap => tap.entities.map(entity => entity.kind)))];
|
|
318
|
+
const types = [...new Set(deps.taps.flatMap(tap => [...tap.types]))];
|
|
319
|
+
/** Load the committed events in the range that some tap wants, and run each matching tap. Errors are logged, never thrown. */
|
|
320
|
+
const dispatch = async (db, payload) => {
|
|
321
|
+
if (deps.taps.length === 0)
|
|
322
|
+
return;
|
|
323
|
+
const range = parseRange(payload);
|
|
324
|
+
if (range === undefined)
|
|
325
|
+
return;
|
|
326
|
+
const rows = await db
|
|
327
|
+
.select()
|
|
328
|
+
.from(eventsTable)
|
|
329
|
+
.where(and(gte(eventsTable.seq, range.from), lte(eventsTable.seq, range.to), inArray(eventsTable.kind, kinds), inArray(eventsTable.type, types)))
|
|
330
|
+
.orderBy(asc(eventsTable.seq));
|
|
331
|
+
for (const row of rows) {
|
|
332
|
+
for (const tap of deps.taps) {
|
|
333
|
+
if (!tap.types.has(row.type) || !tap.entities.some(entity => entity.kind === row.kind))
|
|
334
|
+
continue;
|
|
335
|
+
try {
|
|
336
|
+
const event = deps.history.decodeStoredEvent(row, findEventDefinition(tap.entities, row.kind, row.type), row.entityId);
|
|
337
|
+
await tap.run(event, { db });
|
|
338
|
+
}
|
|
339
|
+
catch (error) {
|
|
340
|
+
debugDrain.debug('tap {tapName}: {rowType} {entityId} failed: {failed}', {
|
|
341
|
+
tapName: tap.name,
|
|
342
|
+
rowType: row.type,
|
|
343
|
+
entityId: row.entityId,
|
|
344
|
+
failed: errorText(error),
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
};
|
|
350
|
+
return dispatch;
|
|
351
|
+
}
|
|
352
|
+
const quiet = () => {
|
|
353
|
+
/* a dispatch failure was logged where it happened */
|
|
354
|
+
};
|
|
355
|
+
export function createWorkers(deps) {
|
|
356
|
+
/** One wake function per running worker this journal started. */
|
|
357
|
+
const wakers = new Set();
|
|
358
|
+
const worker = (db, opts) => {
|
|
359
|
+
assertRootDb(db, 'worker');
|
|
360
|
+
if (deps.tapNames.length > 0 && opts?.listen === undefined && opts?.taps !== false)
|
|
361
|
+
throw new Error(`journal: this journal has taps (${deps.tapNames.join(', ')}) but the worker has no \`listen\`; taps fire only from the wake channel. Wire LISTEN on journal.wakeChannel, or pass { taps: false } for a worker that runs jobs only`);
|
|
362
|
+
const pollMs = opts?.pollMs ?? DEFAULT_POLL_MS;
|
|
363
|
+
let unlisten;
|
|
364
|
+
// Wake payloads dispatch one after another, in the order they arrived.
|
|
365
|
+
let dispatching = Promise.resolve();
|
|
366
|
+
let running = false;
|
|
367
|
+
let loop = Promise.resolve();
|
|
368
|
+
// Aborted by `stop()`. It reaches the running effect as `ctx.signal`, and
|
|
369
|
+
// `drain` claims no further job once it is aborted.
|
|
370
|
+
let stopping = new AbortController();
|
|
371
|
+
let endSleep;
|
|
372
|
+
// A wake that arrived during a pass. That pass may have looked before the
|
|
373
|
+
// commit that caused the wake, so one more pass follows it.
|
|
374
|
+
let woken = false;
|
|
375
|
+
const sleep = () => new Promise(resolve => {
|
|
376
|
+
const timer = setTimeout(() => {
|
|
377
|
+
endSleep = undefined;
|
|
378
|
+
resolve();
|
|
379
|
+
}, pollMs);
|
|
380
|
+
endSleep = () => {
|
|
381
|
+
clearTimeout(timer);
|
|
382
|
+
endSleep = undefined;
|
|
383
|
+
resolve();
|
|
384
|
+
};
|
|
385
|
+
});
|
|
386
|
+
// `stop()` and `wake()` flip these from another call while `run` is awaiting.
|
|
387
|
+
const isRunning = () => running;
|
|
388
|
+
const isWoken = () => woken;
|
|
389
|
+
const run = async () => {
|
|
390
|
+
while (isRunning()) {
|
|
391
|
+
woken = false;
|
|
392
|
+
let processed = 0;
|
|
393
|
+
try {
|
|
394
|
+
processed = await deps.drain(db, {
|
|
395
|
+
batchSize: opts?.batchSize,
|
|
396
|
+
signal: stopping.signal,
|
|
397
|
+
leaseSeconds: opts?.leaseSeconds,
|
|
398
|
+
});
|
|
399
|
+
if (isRunning()) {
|
|
400
|
+
const caught = await deps.catchUp(db);
|
|
401
|
+
processed += caught.scanned;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
catch (error) {
|
|
405
|
+
debugWorker.debug('drain failed: {failed}', { failed: errorText(error) });
|
|
406
|
+
}
|
|
407
|
+
if (isRunning() && processed === 0 && !isWoken())
|
|
408
|
+
await sleep();
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
const wake = () => {
|
|
412
|
+
if (!running)
|
|
413
|
+
return;
|
|
414
|
+
woken = true;
|
|
415
|
+
endSleep?.();
|
|
416
|
+
};
|
|
417
|
+
return {
|
|
418
|
+
async start() {
|
|
419
|
+
if (running)
|
|
420
|
+
return;
|
|
421
|
+
running = true;
|
|
422
|
+
stopping = new AbortController();
|
|
423
|
+
wakers.add(wake);
|
|
424
|
+
if (opts?.listen !== undefined) {
|
|
425
|
+
unlisten = await opts.listen(payload => {
|
|
426
|
+
wake();
|
|
427
|
+
if (opts.taps === false)
|
|
428
|
+
return;
|
|
429
|
+
dispatching = dispatching.then(() => deps.dispatch(db, payload)).catch(quiet);
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
debugWorker.debug('start (poll {pollMs}ms{value2})', {
|
|
433
|
+
pollMs,
|
|
434
|
+
value2: unlisten === undefined ? '' : ', listening',
|
|
435
|
+
});
|
|
436
|
+
loop = run();
|
|
437
|
+
},
|
|
438
|
+
async stop() {
|
|
439
|
+
running = false;
|
|
440
|
+
stopping.abort();
|
|
441
|
+
// eslint-disable-next-line drizzle/enforce-delete-with-where -- Set#delete, not a Drizzle query
|
|
442
|
+
wakers.delete(wake);
|
|
443
|
+
endSleep?.();
|
|
444
|
+
await unlisten?.();
|
|
445
|
+
unlisten = undefined;
|
|
446
|
+
await dispatching;
|
|
447
|
+
await loop;
|
|
448
|
+
debugWorker.debug('stopped');
|
|
449
|
+
},
|
|
450
|
+
wake,
|
|
451
|
+
};
|
|
452
|
+
};
|
|
453
|
+
const wakeAll = () => {
|
|
454
|
+
for (const wake of wakers)
|
|
455
|
+
wake();
|
|
456
|
+
};
|
|
457
|
+
return { worker, wakeAll };
|
|
458
|
+
}
|
|
459
|
+
//# sourceMappingURL=worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"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"}
|
package/dist/write.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The write path: the write algorithm, version ordering of inserted events, and
|
|
3
|
+
* telling an append conflict from other database errors.
|
|
4
|
+
* May import `api`, `fold`, `history`, `storage`, `transaction-guard` and leaf files.
|
|
5
|
+
* Must not import `journal`, `command` or `worker`.
|
|
6
|
+
*/
|
|
7
|
+
import type { z } from 'zod';
|
|
8
|
+
import type { NextEvents, WriteInput, WriteResult } from './api.js';
|
|
9
|
+
import type { History } from './history.js';
|
|
10
|
+
import type { JournalTables } from './pg.js';
|
|
11
|
+
import type { AnyEventDef, Effect, EntityDef, EntityId, EntityTable, Projection, Trace, TransactionSource } from './types.js';
|
|
12
|
+
/** Insert order is the version order. `RETURNING` does not promise it, so restore it. */
|
|
13
|
+
export declare function sortedByVersion<Row extends {
|
|
14
|
+
readonly version: number;
|
|
15
|
+
}>(rows: readonly Row[]): Row[];
|
|
16
|
+
/** What a write needs from the journal. */
|
|
17
|
+
export type WriteDeps<Meta extends z.ZodObject, Tx extends TransactionSource<Tx>> = {
|
|
18
|
+
readonly metaSchema: Meta;
|
|
19
|
+
readonly tables: JournalTables;
|
|
20
|
+
/** Inline projections only: they run inside the write. */
|
|
21
|
+
readonly projections: readonly Projection<z.output<Meta>, Tx>[];
|
|
22
|
+
/** Async projections: the write only wakes the worker when a recorded event matches one. */
|
|
23
|
+
readonly asyncProjections: readonly Pick<Projection, 'types' | 'entities'>[];
|
|
24
|
+
/** A write only queues one job per matching effect. It never runs an effect, so the effect's database type does not matter here. */
|
|
25
|
+
readonly effects: readonly Pick<Effect<z.output<Meta>>, 'name' | 'types' | 'entities' | 'schedule'>[];
|
|
26
|
+
readonly history: Pick<History<Meta>, 'decodeStoredEvent' | 'highestVersion' | 'assertLogSaysGone'>;
|
|
27
|
+
/** Notified at commit with the seq range of every nonempty append. */
|
|
28
|
+
readonly wakeChannel: string;
|
|
29
|
+
};
|
|
30
|
+
export declare function createWriter<Meta extends z.ZodObject, Tx extends TransactionSource<Tx>>(deps: WriteDeps<Meta, Tx>): {
|
|
31
|
+
write: <Tbl extends EntityTable, E extends AnyEventDef, Key extends string>(tx: Tx, entity: EntityDef<string, Tbl, E, z.output<Meta>, Key>, id: EntityId<Tbl, Key>, input: WriteInput<Tbl, E, Meta, Tx>) => Promise<WriteResult<Tbl, E, z.output<Meta>, Key>>;
|
|
32
|
+
adopt: <Tbl extends EntityTable, E extends AnyEventDef, Key extends string>(tx: Tx, entity: EntityDef<string, Tbl, E, z.output<Meta>, Key>, id: EntityId<Tbl, Key>, input: WriteInput<Tbl, E, Meta, Tx>) => Promise<WriteResult<Tbl, E, z.output<Meta>, Key>>;
|
|
33
|
+
writeWithValidatedMeta: <Tbl extends EntityTable, E extends AnyEventDef, Key extends string>(tx: Tx, entity: EntityDef<string, Tbl, E, z.output<Meta>, Key>, id: EntityId<Tbl, Key>, getValidatedMeta: () => z.output<Meta>, events: NextEvents<Tbl, E, Tx>, trace: Trace, onJobs?: (count: number) => void, opts?: {
|
|
34
|
+
readonly mode?: 'write' | 'adopt';
|
|
35
|
+
readonly expectedVersion?: number;
|
|
36
|
+
}) => Promise<WriteResult<Tbl, E, z.output<Meta>, Key>>;
|
|
37
|
+
};
|
|
38
|
+
export type Writer<Meta extends z.ZodObject, Tx extends TransactionSource<Tx>> = ReturnType<typeof createWriter<Meta, Tx>>;
|
|
39
|
+
//# sourceMappingURL=write.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../src/write.ts"],"names":[],"mappings":"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"}
|