pg-boss 12.32.0 → 12.33.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/adapters/pglite.d.ts +1 -0
- package/dist/adapters/pglite.d.ts.map +1 -1
- package/dist/adapters/pglite.js +106 -2
- package/dist/attorney.d.ts.map +1 -1
- package/dist/attorney.js +12 -0
- package/dist/bam.d.ts.map +1 -1
- package/dist/bam.js +10 -5
- package/dist/boss.d.ts.map +1 -1
- package/dist/boss.js +24 -7
- package/dist/claimTimer.d.ts +44 -0
- package/dist/claimTimer.d.ts.map +1 -0
- package/dist/claimTimer.js +95 -0
- package/dist/cli.js +56 -2
- package/dist/clock.d.ts +31 -0
- package/dist/clock.d.ts.map +1 -0
- package/dist/clock.js +156 -0
- package/dist/contractor.d.ts +5 -1
- package/dist/contractor.d.ts.map +1 -1
- package/dist/contractor.js +24 -2
- package/dist/db.d.ts +6 -1
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +50 -6
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +59 -27
- package/dist/manager.d.ts +2 -2
- package/dist/manager.d.ts.map +1 -1
- package/dist/manager.js +17 -17
- package/dist/migrationStore.d.ts.map +1 -1
- package/dist/migrationStore.js +210 -2
- package/dist/navigator.d.ts.map +1 -1
- package/dist/navigator.js +10 -5
- package/dist/plans.d.ts +17 -2
- package/dist/plans.d.ts.map +1 -1
- package/dist/plans.js +203 -83
- package/dist/schema.json +11 -3
- package/dist/timekeeper.d.ts +12 -6
- package/dist/timekeeper.d.ts.map +1 -1
- package/dist/timekeeper.js +64 -20
- package/dist/tools.d.ts +9 -3
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +35 -8
- package/dist/types.d.ts +50 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/worker.d.ts +3 -1
- package/dist/worker.d.ts.map +1 -1
- package/dist/worker.js +12 -9
- package/package.json +6 -3
package/dist/clock.js
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { setImmediate } from 'node:timers/promises';
|
|
2
|
+
import * as plans from "./plans.js";
|
|
3
|
+
export const systemClock = {
|
|
4
|
+
now: () => Date.now(),
|
|
5
|
+
setTimeout: (fn, ms) => setTimeout(fn, ms),
|
|
6
|
+
clearTimeout: (handle) => clearTimeout(handle),
|
|
7
|
+
setInterval: (fn, ms) => setInterval(fn, ms),
|
|
8
|
+
clearInterval: (handle) => clearInterval(handle)
|
|
9
|
+
};
|
|
10
|
+
export function isAttachable(clock) {
|
|
11
|
+
return typeof clock.attach === 'function';
|
|
12
|
+
}
|
|
13
|
+
function toMillis(t) {
|
|
14
|
+
const ms = t instanceof Date ? t.getTime() : typeof t === 'number' ? t : new Date(t).getTime();
|
|
15
|
+
if (!Number.isFinite(ms)) {
|
|
16
|
+
throw new Error(`TestClock: invalid time ${String(t)}`);
|
|
17
|
+
}
|
|
18
|
+
return ms;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* A clock a test drives by hand. Time only moves through setTime() and tick(); timers only fire
|
|
22
|
+
* from tick(). When attached to a schema, every pg-boss statement there reads the same time
|
|
23
|
+
* through ${schema}.job_now(), so JavaScript and Postgres agree on what "now" is.
|
|
24
|
+
*/
|
|
25
|
+
export class TestClock {
|
|
26
|
+
#now;
|
|
27
|
+
#timers = [];
|
|
28
|
+
#seq = 0;
|
|
29
|
+
#ticking = false;
|
|
30
|
+
// Every (db, schema) this clock currently pushes time to. More than one because a multi-instance
|
|
31
|
+
// test shares one clock across several PgBoss instances, each of which attaches on start(). The
|
|
32
|
+
// schema is shared, so the last handle to be disposed is the one that restores job_now() and
|
|
33
|
+
// drops the clock table; the session opt-in is separate, and each instance drops its own.
|
|
34
|
+
#targets = [];
|
|
35
|
+
constructor(start = Date.now()) {
|
|
36
|
+
this.#now = toMillis(start);
|
|
37
|
+
}
|
|
38
|
+
now() {
|
|
39
|
+
return this.#now;
|
|
40
|
+
}
|
|
41
|
+
setTimeout(fn, ms) {
|
|
42
|
+
return this.#schedule(fn, ms, null);
|
|
43
|
+
}
|
|
44
|
+
setInterval(fn, ms) {
|
|
45
|
+
return this.#schedule(fn, ms, Math.max(ms, 1));
|
|
46
|
+
}
|
|
47
|
+
clearTimeout(handle) {
|
|
48
|
+
const i = this.#timers.indexOf(handle);
|
|
49
|
+
if (i !== -1)
|
|
50
|
+
this.#timers.splice(i, 1);
|
|
51
|
+
}
|
|
52
|
+
clearInterval(handle) {
|
|
53
|
+
this.clearTimeout(handle);
|
|
54
|
+
}
|
|
55
|
+
/** Jumps to a time, forwards or backwards, firing nothing. */
|
|
56
|
+
async setTime(t) {
|
|
57
|
+
this.#now = toMillis(t);
|
|
58
|
+
await this.#push();
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Advances by ms, firing each due timer in order at its own due time. Does not wait for I/O the
|
|
62
|
+
* callbacks start; observe effects with spies or by querying.
|
|
63
|
+
*/
|
|
64
|
+
async tick(ms) {
|
|
65
|
+
if (this.#ticking) {
|
|
66
|
+
throw new Error('TestClock: tick() called while a tick is in progress');
|
|
67
|
+
}
|
|
68
|
+
this.#ticking = true;
|
|
69
|
+
try {
|
|
70
|
+
const target = this.#now + ms;
|
|
71
|
+
while (this.#timers.length && this.#timers[0].due <= target) {
|
|
72
|
+
const timer = this.#timers.shift();
|
|
73
|
+
if (timer.due > this.#now) {
|
|
74
|
+
this.#now = timer.due;
|
|
75
|
+
await this.#push();
|
|
76
|
+
}
|
|
77
|
+
// Reinsert the same object so the handle handed out by setInterval still clears it.
|
|
78
|
+
if (timer.interval !== null) {
|
|
79
|
+
timer.due += timer.interval;
|
|
80
|
+
timer.seq = this.#seq++;
|
|
81
|
+
this.#insert(timer);
|
|
82
|
+
}
|
|
83
|
+
timer.fn();
|
|
84
|
+
await setImmediate();
|
|
85
|
+
}
|
|
86
|
+
this.#now = target;
|
|
87
|
+
await this.#push();
|
|
88
|
+
await setImmediate();
|
|
89
|
+
}
|
|
90
|
+
finally {
|
|
91
|
+
this.#ticking = false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
async attach(target) {
|
|
95
|
+
const { db, schema } = target;
|
|
96
|
+
// One batch, so the override function is never visible over an empty table: the body reads the
|
|
97
|
+
// single row and COALESCEs to pg_catalog.now() when it finds none, so a seed in a second round
|
|
98
|
+
// trip would serve real time to anything calling job_now() in between. The timestamp is a
|
|
99
|
+
// literal because a parameterised statement cannot carry more than one command; it is derived
|
|
100
|
+
// from this.#now, a number, so there is nothing here to inject.
|
|
101
|
+
//
|
|
102
|
+
// Dropped and recreated rather than IF NOT EXISTS: adopting a table that is already there would
|
|
103
|
+
// mean wiping rows this clock did not write, and dropping it on release. The name is one nobody
|
|
104
|
+
// else would pick, so a table under it is always a leftover from a killed run and safe to take.
|
|
105
|
+
await db.executeSql(`
|
|
106
|
+
DROP TABLE IF EXISTS ${plans.clockTable(schema)};
|
|
107
|
+
CREATE TABLE ${plans.clockTable(schema)} (now timestamp with time zone NOT NULL);
|
|
108
|
+
${plans.createClockFunction(schema, { replace: true, body: plans.clockOverrideBody(schema) })}
|
|
109
|
+
INSERT INTO ${plans.clockTable(schema)} (now) VALUES (to_timestamp(${this.#now / 1000}));
|
|
110
|
+
`);
|
|
111
|
+
// The session opt-in is not issued here. attach() runs after the contractor has already opened
|
|
112
|
+
// connections and migrated, so a SET on this one session would miss every other one. PgBoss
|
|
113
|
+
// declares it through db.setSessionStatements() before anything opens; see #doStart.
|
|
114
|
+
const entry = { db, schema };
|
|
115
|
+
this.#targets.push(entry);
|
|
116
|
+
let disposed = false;
|
|
117
|
+
return {
|
|
118
|
+
[Symbol.asyncDispose]: async () => {
|
|
119
|
+
if (disposed)
|
|
120
|
+
return;
|
|
121
|
+
disposed = true;
|
|
122
|
+
this.#targets.splice(this.#targets.indexOf(entry), 1);
|
|
123
|
+
if (!this.#targets.some(t => t.schema === schema)) {
|
|
124
|
+
await db.executeSql(`
|
|
125
|
+
${plans.createClockFunction(schema, { replace: true })}
|
|
126
|
+
DROP TABLE IF EXISTS ${plans.clockTable(schema)};
|
|
127
|
+
${plans.disableClockOverride()};
|
|
128
|
+
`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
#schedule(fn, ms, interval) {
|
|
134
|
+
const timer = { fn, due: this.#now + Math.max(ms, 0), seq: this.#seq++, interval };
|
|
135
|
+
this.#insert(timer);
|
|
136
|
+
return timer;
|
|
137
|
+
}
|
|
138
|
+
// Keeps #timers sorted by due time, then by scheduling order for equal due times, so tick() can
|
|
139
|
+
// always take the next timer from the front.
|
|
140
|
+
#insert(timer) {
|
|
141
|
+
let i = this.#timers.length;
|
|
142
|
+
while (i > 0) {
|
|
143
|
+
const previous = this.#timers[i - 1];
|
|
144
|
+
const laterDue = previous.due > timer.due;
|
|
145
|
+
const sameDueScheduledLater = previous.due === timer.due && previous.seq > timer.seq;
|
|
146
|
+
if (!laterDue && !sameDueScheduledLater)
|
|
147
|
+
break;
|
|
148
|
+
i--;
|
|
149
|
+
}
|
|
150
|
+
this.#timers.splice(i, 0, timer);
|
|
151
|
+
}
|
|
152
|
+
async #push() {
|
|
153
|
+
const seconds = this.#now / 1000;
|
|
154
|
+
await Promise.all(this.#targets.map(({ db, schema }) => db.executeSql(`UPDATE ${plans.clockTable(schema)} SET now = to_timestamp($1)`, [seconds])));
|
|
155
|
+
}
|
|
156
|
+
}
|
package/dist/contractor.d.ts
CHANGED
|
@@ -11,7 +11,11 @@ declare class Contractor {
|
|
|
11
11
|
isInstalled(): Promise<boolean>;
|
|
12
12
|
start(): Promise<void>;
|
|
13
13
|
private assertNoSchemaCaseVariant;
|
|
14
|
-
detectDrift(
|
|
14
|
+
detectDrift(options?: {
|
|
15
|
+
clockOverride?: boolean;
|
|
16
|
+
}): Promise<types.SchemaDriftReport>;
|
|
17
|
+
detectClockOverride(): Promise<boolean>;
|
|
18
|
+
restoreClockFunction(): Promise<void>;
|
|
15
19
|
check(): Promise<void>;
|
|
16
20
|
create(): Promise<void>;
|
|
17
21
|
migrate(version: number): Promise<void>;
|
package/dist/contractor.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contractor.d.ts","sourceRoot":"","sources":["../src/contractor.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,KAAK,KAAK,MAAM,YAAY,CAAA;AAkBxC,cAAM,UAAU;IACd,MAAM,CAAC,iBAAiB,CAAE,MAAM,SAAuB,EAAE,OAAO,GAAE,KAAK,CAAC,uBAA4B;IAapG,MAAM,CAAC,cAAc,CAAE,MAAM,SAAuB,EAAE,OAAO,SAAoB,EAAE,OAAO,GAAE,KAAK,CAAC,oBAAyB;IAS3H,MAAM,CAAC,aAAa,CAAE,MAAM,SAAuB,EAAE,OAAO,SAAgB,EAAE,OAAO,GAAE,KAAK,CAAC,WAAgB;IAM7G,OAAO,CAAC,MAAM,CAAkC;IAChD,OAAO,CAAC,EAAE,CAAiB;IAC3B,OAAO,CAAC,UAAU,CAAmB;gBAExB,EAAE,EAAE,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,0BAA0B;IAgBpE,aAAa;IAKb,WAAW;IAKX,KAAK;YAsBG,yBAAyB;IAkCjC,WAAW,
|
|
1
|
+
{"version":3,"file":"contractor.d.ts","sourceRoot":"","sources":["../src/contractor.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,KAAK,KAAK,MAAM,YAAY,CAAA;AAkBxC,cAAM,UAAU;IACd,MAAM,CAAC,iBAAiB,CAAE,MAAM,SAAuB,EAAE,OAAO,GAAE,KAAK,CAAC,uBAA4B;IAapG,MAAM,CAAC,cAAc,CAAE,MAAM,SAAuB,EAAE,OAAO,SAAoB,EAAE,OAAO,GAAE,KAAK,CAAC,oBAAyB;IAS3H,MAAM,CAAC,aAAa,CAAE,MAAM,SAAuB,EAAE,OAAO,SAAgB,EAAE,OAAO,GAAE,KAAK,CAAC,WAAgB;IAM7G,OAAO,CAAC,MAAM,CAAkC;IAChD,OAAO,CAAC,EAAE,CAAiB;IAC3B,OAAO,CAAC,UAAU,CAAmB;gBAExB,EAAE,EAAE,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,0BAA0B;IAgBpE,aAAa;IAKb,WAAW;IAKX,KAAK;YAsBG,yBAAyB;IAkCjC,WAAW,CAAE,OAAO,GAAE;QAAE,aAAa,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,OAAO,CAAC,KAAK,CAAC,iBAAiB,CAAC;IAsHzF,mBAAmB,IAAK,OAAO,CAAC,OAAO,CAAC;IASxC,oBAAoB,IAAK,OAAO,CAAC,IAAI,CAAC;IAItC,KAAK;IAcL,MAAM;IASN,OAAO,CAAE,OAAO,EAAE,MAAM;IASxB,IAAI,CAAE,OAAO,EAAE,MAAM;IAKrB,QAAQ,CAAE,OAAO,EAAE,MAAM;CAIhC;AAED,eAAe,UAAU,CAAA"}
|
package/dist/contractor.js
CHANGED
|
@@ -113,7 +113,7 @@ class Contractor {
|
|
|
113
113
|
// Presence-level schema drift scan: compares the managed indexes the code expects against the live
|
|
114
114
|
// catalog. Partitioned vs. non-partitioned is read from the database (job_common presence), and the
|
|
115
115
|
// per-queue policy indexes are computed from the queue table, so conditional indexes are handled.
|
|
116
|
-
async detectDrift() {
|
|
116
|
+
async detectDrift(options = {}) {
|
|
117
117
|
const schema = this.config.schema;
|
|
118
118
|
const probe = await this.db.executeSql(plans.jobCommonExists(schema));
|
|
119
119
|
const partitioned = !!probe.rows[0].name;
|
|
@@ -206,12 +206,34 @@ class Contractor {
|
|
|
206
206
|
return drifter.computeSchemaDrift({
|
|
207
207
|
indexes: { expected: expectedIndexes, live, building },
|
|
208
208
|
tables: { expected: plans.expectedManagedTables(schema, partitioned, partitions), live: liveTables ?? [...new Set(liveColumns.map(c => c.table))] },
|
|
209
|
-
functions: functionsSupported ? { expected: plans.expectedManagedFunctions(schema, partitioned), live: liveFunctions } : undefined,
|
|
209
|
+
functions: functionsSupported ? { expected: plans.expectedManagedFunctions(schema, partitioned, options), live: liveFunctions } : undefined,
|
|
210
210
|
columns: { expected: expectedColumns, live: liveColumns },
|
|
211
211
|
constraints: canonicalPg ? { expected: plans.expectedManagedConstraints(schema, partitioned), live: liveConstraints } : undefined,
|
|
212
212
|
enum: { name: 'job_state', expected: plans.EXPECTED_JOB_STATES, actual: enumLabels }
|
|
213
213
|
});
|
|
214
214
|
}
|
|
215
|
+
// A TestClock swaps the body of job_now() and only puts it back when its handle is disposed, so a
|
|
216
|
+
// run killed mid-test (Ctrl-C, a crashed suite, a bailed runner) leaves the override installed.
|
|
217
|
+
// Correctness survives - the body falls through to pg_catalog.now() for any session that has not
|
|
218
|
+
// opted in - but the override's subquery defeats inlining, so every statement that reads the clock
|
|
219
|
+
// pays a per-row function call instead of a constant-folded timestamp, permanently and silently.
|
|
220
|
+
// The leftover travels with the database, which matters most for an embedded one whose data
|
|
221
|
+
// directory gets committed or shipped.
|
|
222
|
+
//
|
|
223
|
+
// Best-effort in both directions: a backend or a role that cannot read pg_proc is not evidence of
|
|
224
|
+
// a problem, and must never block a start that would otherwise succeed.
|
|
225
|
+
async detectClockOverride() {
|
|
226
|
+
try {
|
|
227
|
+
const result = await this.db.executeSql(plans.getClockFunctionSource(this.config.schema));
|
|
228
|
+
return plans.clockFunctionIsOverridden(result.rows[0]?.source);
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
async restoreClockFunction() {
|
|
235
|
+
await this.db.executeSql(plans.restoreClockFunction(this.config.schema));
|
|
236
|
+
}
|
|
215
237
|
async check() {
|
|
216
238
|
const installed = await this.isInstalled();
|
|
217
239
|
if (!installed) {
|
package/dist/db.d.ts
CHANGED
|
@@ -4,13 +4,18 @@ export declare const TRANSACTION_ROLLBACK_TIMEOUT_MS = 5000;
|
|
|
4
4
|
declare class Db extends EventEmitter implements types.IDatabase, types.EventsMixin {
|
|
5
5
|
private pool;
|
|
6
6
|
private config;
|
|
7
|
+
private clock;
|
|
8
|
+
private sessionStatements;
|
|
7
9
|
opened: boolean;
|
|
8
|
-
constructor(config: types.DatabaseOptions
|
|
10
|
+
constructor(config: types.DatabaseOptions & {
|
|
11
|
+
clock?: types.Clock;
|
|
12
|
+
});
|
|
9
13
|
events: {
|
|
10
14
|
error: string;
|
|
11
15
|
};
|
|
12
16
|
open(): Promise<void>;
|
|
13
17
|
close(): Promise<void>;
|
|
18
|
+
setSessionStatements(statements: string[]): Promise<void>;
|
|
14
19
|
executeSql(text: string, values?: unknown[]): Promise<import("pg").QueryResult<any>>;
|
|
15
20
|
listen(channel: string, onNotification: (payload: string) => void, onReconnect: () => void): Promise<types.ListenHandle>;
|
|
16
21
|
beginTransaction(): Promise<types.TransactionHandle>;
|
package/dist/db.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,aAAa,CAAA;AAItC,OAAO,KAAK,KAAK,KAAK,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,aAAa,CAAA;AAItC,OAAO,KAAK,KAAK,KAAK,MAAM,YAAY,CAAA;AAaxC,eAAO,MAAM,+BAA+B,OAAO,CAAA;AAEnD,cAAM,EAAG,SAAQ,YAAa,YAAW,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,WAAW;IACzE,OAAO,CAAC,IAAI,CAAU;IACtB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,KAAK,CAAa;IAG1B,OAAO,CAAC,iBAAiB,CAAe;IAGxC,MAAM,EAAE,OAAO,CAAA;gBAEF,MAAM,EAAE,KAAK,CAAC,eAAe,GAAG;QAAE,KAAK,CAAC,EAAE,KAAK,CAAC,KAAK,CAAA;KAAE;IAcpE,MAAM;;MAEL;IAEK,IAAI;IAgBJ,KAAK;IAOL,oBAAoB,CAAE,UAAU,EAAE,MAAM,EAAE;IAoC1C,UAAU,CAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE;IAqB5C,MAAM,CACV,OAAO,EAAE,MAAM,EACf,cAAc,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,EACzC,WAAW,EAAE,MAAM,IAAI,GACtB,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC;IA2JxB,gBAAgB,IAAK,OAAO,CAAC,KAAK,CAAC,iBAAiB,CAAC;IAsFrD,eAAe,CAAC,CAAC,EAAG,EAAE,EAAE,CAAC,EAAE,EAAE,KAAK,CAAC,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;CAY/E;AAED,eAAe,EAAE,CAAA"}
|
package/dist/db.js
CHANGED
|
@@ -2,6 +2,7 @@ import EventEmitter from 'node:events';
|
|
|
2
2
|
import pg from 'pg';
|
|
3
3
|
import assert from 'node:assert';
|
|
4
4
|
import { delay } from "./tools.js";
|
|
5
|
+
import { systemClock } from "./clock.js";
|
|
5
6
|
// Keep silent network failures below the default 30-second notify polling backstop: in the
|
|
6
7
|
// worst case a failure happens immediately after a successful check, then takes one interval,
|
|
7
8
|
// one query timeout, and the existing first reconnect backoff (1s) to restore LISTEN.
|
|
@@ -15,11 +16,16 @@ export const TRANSACTION_ROLLBACK_TIMEOUT_MS = 5000;
|
|
|
15
16
|
class Db extends EventEmitter {
|
|
16
17
|
pool;
|
|
17
18
|
config;
|
|
19
|
+
clock;
|
|
20
|
+
// Statements every pooled connection must run before it is handed out. Set by PgBoss during
|
|
21
|
+
// start(), before open(), so no connection this pool creates can miss them.
|
|
22
|
+
sessionStatements = [];
|
|
18
23
|
/** @internal */
|
|
19
24
|
_pgbdb;
|
|
20
25
|
opened;
|
|
21
26
|
constructor(config) {
|
|
22
27
|
super();
|
|
28
|
+
this.clock = config.clock ?? systemClock;
|
|
23
29
|
config.application_name = config.application_name || 'pgboss';
|
|
24
30
|
config.connectionTimeoutMillis ??= 10000;
|
|
25
31
|
// config.maxUses = config.maxUses || 1000
|
|
@@ -33,6 +39,14 @@ class Db extends EventEmitter {
|
|
|
33
39
|
async open() {
|
|
34
40
|
this.pool = new pg.Pool(this.config);
|
|
35
41
|
this.pool.on('error', error => this.emit('error', error));
|
|
42
|
+
// Queued on the client before any checkout query, so a connection cannot run a pg-boss
|
|
43
|
+
// statement before its session setup. Reads the field on each connect rather than closing over
|
|
44
|
+
// it, so a set that arrives between connections still applies to the ones that follow.
|
|
45
|
+
this.pool.on('connect', client => {
|
|
46
|
+
for (const statement of this.sessionStatements) {
|
|
47
|
+
client.query(statement).catch(error => this.emit('error', error));
|
|
48
|
+
}
|
|
49
|
+
});
|
|
36
50
|
this.opened = true;
|
|
37
51
|
}
|
|
38
52
|
async close() {
|
|
@@ -41,6 +55,36 @@ class Db extends EventEmitter {
|
|
|
41
55
|
await this.pool.end();
|
|
42
56
|
}
|
|
43
57
|
}
|
|
58
|
+
async setSessionStatements(statements) {
|
|
59
|
+
// Clearing is always safe: the statements it would have run are the ones already applied, and
|
|
60
|
+
// undoing them is the caller's job.
|
|
61
|
+
if (!this.opened || statements.length === 0) {
|
|
62
|
+
this.sessionStatements = statements;
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
// An open pool holds connections that will never re-run the connect hook, so a non-empty set
|
|
66
|
+
// arriving now would reach some sessions and not others - exactly the split this capability
|
|
67
|
+
// exists to prevent. It can still be made total while nothing is checked out (a restart after
|
|
68
|
+
// stop({ close: false }) is the case that matters): every existing connection is idle, so it
|
|
69
|
+
// can be taken and set up here, and every later one gets the hook. With a connection in use
|
|
70
|
+
// there is no way to reach it, so refuse instead of applying a partial set.
|
|
71
|
+
assert(this.pool.idleCount === this.pool.totalCount && this.pool.waitingCount === 0, 'configuration assert: setSessionStatements cannot reach connections that are already checked out - call it before open(), or while the pool is idle');
|
|
72
|
+
// Set first, so a connection the checkout below has to create runs the statements through the
|
|
73
|
+
// connect hook rather than being missed by a sweep that already counted it.
|
|
74
|
+
this.sessionStatements = statements;
|
|
75
|
+
const clients = await Promise.all(Array.from({ length: this.pool.totalCount }, async () => await this.pool.connect()));
|
|
76
|
+
try {
|
|
77
|
+
await Promise.all(clients.map(async (client) => {
|
|
78
|
+
for (const statement of statements) {
|
|
79
|
+
await client.query(statement);
|
|
80
|
+
}
|
|
81
|
+
}));
|
|
82
|
+
}
|
|
83
|
+
finally {
|
|
84
|
+
for (const client of clients)
|
|
85
|
+
client.release();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
44
88
|
async executeSql(text, values) {
|
|
45
89
|
assert(this.opened, 'Database not opened. Call open() before executing SQL.');
|
|
46
90
|
// if (this.config.debug === true) {
|
|
@@ -77,7 +121,7 @@ class Db extends EventEmitter {
|
|
|
77
121
|
const clearHeartbeat = () => {
|
|
78
122
|
if (!heartbeatTimer)
|
|
79
123
|
return;
|
|
80
|
-
clearTimeout(heartbeatTimer);
|
|
124
|
+
this.clock.clearTimeout(heartbeatTimer);
|
|
81
125
|
heartbeatTimer = null;
|
|
82
126
|
};
|
|
83
127
|
const scheduleReconnect = () => {
|
|
@@ -85,7 +129,7 @@ class Db extends EventEmitter {
|
|
|
85
129
|
return;
|
|
86
130
|
const backoff = Math.min(30000, 1000 * 2 ** Math.min(attempt, 5));
|
|
87
131
|
attempt++;
|
|
88
|
-
reconnectTimer = setTimeout(() => {
|
|
132
|
+
reconnectTimer = this.clock.setTimeout(() => {
|
|
89
133
|
reconnectTimer = null;
|
|
90
134
|
connect().catch(() => scheduleReconnect());
|
|
91
135
|
}, backoff);
|
|
@@ -104,7 +148,7 @@ class Db extends EventEmitter {
|
|
|
104
148
|
const scheduleHeartbeat = (target) => {
|
|
105
149
|
if (closed || client !== target)
|
|
106
150
|
return;
|
|
107
|
-
heartbeatTimer = setTimeout(() => {
|
|
151
|
+
heartbeatTimer = this.clock.setTimeout(() => {
|
|
108
152
|
heartbeatTimer = null;
|
|
109
153
|
heartbeat(target).catch(error => disconnect(target, error));
|
|
110
154
|
}, heartbeatInterval);
|
|
@@ -123,7 +167,7 @@ class Db extends EventEmitter {
|
|
|
123
167
|
const result = await Promise.race([
|
|
124
168
|
query,
|
|
125
169
|
new Promise((resolve, reject) => {
|
|
126
|
-
timeout = setTimeout(() => reject(new Error('LISTEN/NOTIFY heartbeat timed out')), heartbeatTimeout);
|
|
170
|
+
timeout = this.clock.setTimeout(() => reject(new Error('LISTEN/NOTIFY heartbeat timed out')), heartbeatTimeout);
|
|
127
171
|
})
|
|
128
172
|
]);
|
|
129
173
|
if (!result.rows[0]?.listening) {
|
|
@@ -132,7 +176,7 @@ class Db extends EventEmitter {
|
|
|
132
176
|
}
|
|
133
177
|
finally {
|
|
134
178
|
if (timeout)
|
|
135
|
-
clearTimeout(timeout);
|
|
179
|
+
this.clock.clearTimeout(timeout);
|
|
136
180
|
}
|
|
137
181
|
scheduleHeartbeat(target);
|
|
138
182
|
};
|
|
@@ -179,7 +223,7 @@ class Db extends EventEmitter {
|
|
|
179
223
|
close: async () => {
|
|
180
224
|
closed = true;
|
|
181
225
|
if (reconnectTimer) {
|
|
182
|
-
clearTimeout(reconnectTimer);
|
|
226
|
+
this.clock.clearTimeout(reconnectTimer);
|
|
183
227
|
reconnectTimer = null;
|
|
184
228
|
}
|
|
185
229
|
clearHeartbeat();
|
package/dist/index.d.ts
CHANGED
|
@@ -109,7 +109,9 @@ export declare class PgBoss extends EventEmitter<types.PgBossEventMap> {
|
|
|
109
109
|
getBamEntries(): Promise<types.BamEntry[]>;
|
|
110
110
|
getDb(): types.IDatabase;
|
|
111
111
|
}
|
|
112
|
-
export
|
|
112
|
+
export { systemClock, TestClock } from './clock.ts';
|
|
113
|
+
export { CLOCK_OVERRIDE_SETTING, enableClockOverride, disableClockOverride } from './plans.ts';
|
|
114
|
+
export type { BackendProfile, BackendOptions, AttachableClock, Clock, ClockTimer, BamEntry, BamEvent, BamStatusSummary, CommandResponse, CompleteOptions, ConnectionOptions, ConstructorOptions, DatabaseOptions, FetchGroupConcurrencyOptions, DependencyRef, FetchOptions, FindJobsOptions, FlowJob, GroupConcurrencyConfig, GroupOptions, IDatabase as Db, InsertOptions, IndexBloat, IndexBloatOptions, InvalidIndex, Job, JobFetchOptions, JobInsert, JobMatchStrategy, JobOptions, JobPollingOptions, JobResult, JobResultStatus, JobStates, Events, JobWithMetadata, MaintenanceOptions, ManagedIndex, MigrationPartition, AsyncMigrationCommand, MismatchedIndex, ManagedFunction, MismatchedFunction, TableColumnDrift, ConstraintDrift, EnumDrift, OffWorkOptions, PgBossEventMap, PreviewScheduleOptions, Queue, QueueOptions, QueuePolicy, QueueResult, QueueStats, QueueStatsOptions, RedriveOptions, ReindexOptions, Request, Schedule, ScheduleKind, ScheduleOptions, SchedulingOptions, SchemaDriftReport, SendOptions, StopOptions, SuperviseOptions, UpdateOptions, UpdateQueueOptions, UpdateRequest, UpdateResponse, UpsertResponse, Warning, WipData, WorkConcurrencyOptions, WorkerState, WorkHandler, WorkOptions, WorkWithMetadataHandler, WorkHandlerFor, PerJobWorkHandler, PerJobWorkWithMetadataHandler, } from './types.ts';
|
|
113
115
|
export type { JobSpyInterface, JobSpyState, JobDataSelector, JobSelector, SpyJob, } from './spy.ts';
|
|
114
116
|
export { fromKnex, fromKysely, fromDrizzle, fromPrisma, fromPglite, fromBunSql, } from './adapters/index.ts';
|
|
115
117
|
export type { KnexTransactionLike, KyselyTransactionLike, DrizzleTransactionLike, DrizzleSqlTagLike, PrismaTransactionLike, PGliteLike, BunSqlLike, BunReservedSqlLike, } from './adapters/index.ts';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import assert from 'node:assert';
|
|
1
2
|
import EventEmitter from 'node:events';
|
|
2
3
|
import * as Attorney from "./attorney.js";
|
|
3
4
|
import Contractor from "./contractor.js";
|
|
@@ -8,6 +9,7 @@ import Bam from "./bam.js";
|
|
|
8
9
|
import Navigator from "./navigator.js";
|
|
9
10
|
import Notifier from "./notifier.js";
|
|
10
11
|
import { delay } from "./tools.js";
|
|
12
|
+
import { isAttachable } from "./clock.js";
|
|
11
13
|
import * as plans from "./plans.js";
|
|
12
14
|
import DbDefault from "./db.js";
|
|
13
15
|
export { JOB_STATES as states } from "./plans.js";
|
|
@@ -41,11 +43,11 @@ export function getRollbackPlans(schema, version, options) {
|
|
|
41
43
|
return Contractor.rollbackPlans(schema, version, options);
|
|
42
44
|
}
|
|
43
45
|
export class PgBoss extends EventEmitter {
|
|
44
|
-
#stoppingOn;
|
|
45
46
|
#stopped;
|
|
46
47
|
#started;
|
|
47
48
|
#startingPromise = null;
|
|
48
49
|
#stoppingPromise = null;
|
|
50
|
+
#attachedClock = null;
|
|
49
51
|
#config;
|
|
50
52
|
#db;
|
|
51
53
|
#boss;
|
|
@@ -57,7 +59,6 @@ export class PgBoss extends EventEmitter {
|
|
|
57
59
|
#notifier;
|
|
58
60
|
constructor(value) {
|
|
59
61
|
super();
|
|
60
|
-
this.#stoppingOn = null;
|
|
61
62
|
this.#stopped = true;
|
|
62
63
|
const config = Attorney.getConfig(value);
|
|
63
64
|
this.#config = config;
|
|
@@ -122,6 +123,14 @@ export class PgBoss extends EventEmitter {
|
|
|
122
123
|
}
|
|
123
124
|
}
|
|
124
125
|
async #doStart() {
|
|
126
|
+
// Before anything opens a connection or runs a statement. The schema clock is gated on a
|
|
127
|
+
// session setting, and a session that misses it reads real time while its peers read fake
|
|
128
|
+
// time - silently, and differently on every checkout. Declaring the setup here means no
|
|
129
|
+
// connection the adapter opens for the contractor, or for any later work, can predate it.
|
|
130
|
+
if (isAttachable(this.#config.clock)) {
|
|
131
|
+
assert(typeof this.#db.setSessionStatements === 'function', 'configuration assert: this db adapter does not implement setSessionStatements(), so a TestClock cannot reach every session it opens. Implement it to run the given statements on each new connection (or once, if the adapter has a single session).');
|
|
132
|
+
await this.#db.setSessionStatements([plans.enableClockOverride()]);
|
|
133
|
+
}
|
|
125
134
|
if (this.#db._pgbdb && !this.#db.opened) {
|
|
126
135
|
await this.#db.open();
|
|
127
136
|
}
|
|
@@ -132,6 +141,9 @@ export class PgBoss extends EventEmitter {
|
|
|
132
141
|
else {
|
|
133
142
|
await this.#contractor.check();
|
|
134
143
|
}
|
|
144
|
+
if (isAttachable(this.#config.clock)) {
|
|
145
|
+
this.#attachedClock = await this.#config.clock.attach({ db: this.#db, schema: this.#config.schema });
|
|
146
|
+
}
|
|
135
147
|
await this.#manager.start();
|
|
136
148
|
if (this.#config.useListenNotify) {
|
|
137
149
|
await this.#notifier.start();
|
|
@@ -197,7 +209,6 @@ export class PgBoss extends EventEmitter {
|
|
|
197
209
|
return;
|
|
198
210
|
}
|
|
199
211
|
timeout = Math.max(timeout, 1000);
|
|
200
|
-
this.#stoppingOn = Date.now();
|
|
201
212
|
this.#stoppingPromise = this.#doStop(close, graceful, timeout);
|
|
202
213
|
try {
|
|
203
214
|
return await this.#stoppingPromise;
|
|
@@ -207,36 +218,55 @@ export class PgBoss extends EventEmitter {
|
|
|
207
218
|
}
|
|
208
219
|
}
|
|
209
220
|
async #doStop(close, graceful, timeout) {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
+
await this.#notifier.stop();
|
|
222
|
+
await this.#manager.stop();
|
|
223
|
+
await this.#timekeeper.stop();
|
|
224
|
+
await this.#boss.stop();
|
|
225
|
+
await this.#navigator.stop();
|
|
226
|
+
await this.#bam.stop();
|
|
227
|
+
const shutdown = async () => {
|
|
228
|
+
await this.#manager.failWip();
|
|
229
|
+
const attachment = this.#attachedClock;
|
|
230
|
+
this.#attachedClock = null;
|
|
231
|
+
try {
|
|
232
|
+
if (attachment) {
|
|
233
|
+
await attachment[Symbol.asyncDispose]();
|
|
221
234
|
}
|
|
222
|
-
this.#stopped = true;
|
|
223
|
-
this.#started = false;
|
|
224
|
-
this.emit(events.stopped);
|
|
225
|
-
};
|
|
226
|
-
if (!graceful) {
|
|
227
|
-
await shutdown();
|
|
228
|
-
return;
|
|
229
235
|
}
|
|
230
|
-
|
|
231
|
-
|
|
236
|
+
finally {
|
|
237
|
+
// Stop stamping the opt-in on connections opened after this point. Harmless if it lingers
|
|
238
|
+
// - dispose restores the plain function body, which never reads the setting - but an
|
|
239
|
+
// instance restarted without a clock should not keep setting it. Undone on the same
|
|
240
|
+
// condition #doStart declared it on, so a start() that threw before attach() and a dispose
|
|
241
|
+
// that fails both still clear it.
|
|
242
|
+
if (isAttachable(this.#config.clock)) {
|
|
243
|
+
await this.#db.setSessionStatements?.([]);
|
|
244
|
+
}
|
|
232
245
|
}
|
|
246
|
+
if (close) {
|
|
247
|
+
await this.#closeDb();
|
|
248
|
+
}
|
|
249
|
+
this.#stopped = true;
|
|
250
|
+
this.#started = false;
|
|
251
|
+
this.emit(events.stopped);
|
|
252
|
+
};
|
|
253
|
+
if (!graceful) {
|
|
233
254
|
await shutdown();
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
// Real time, not the configured clock: the deadline bounds shutdown I/O, and under a test
|
|
258
|
+
// clock nothing would tick it while the test is blocked inside stop().
|
|
259
|
+
const deadline = { reached: false };
|
|
260
|
+
const deadlineTimer = setTimeout(() => { deadline.reached = true; }, timeout);
|
|
261
|
+
try {
|
|
262
|
+
while (!deadline.reached && this.#manager.hasPendingCleanups()) {
|
|
263
|
+
await delay(500);
|
|
264
|
+
}
|
|
234
265
|
}
|
|
235
266
|
finally {
|
|
236
|
-
|
|
237
|
-
// instead of every future stop()/start() call silently no-op-ing forever on the stale marker.
|
|
238
|
-
this.#stoppingOn = null;
|
|
267
|
+
clearTimeout(deadlineTimer);
|
|
239
268
|
}
|
|
269
|
+
await shutdown();
|
|
240
270
|
}
|
|
241
271
|
async #closeDb() {
|
|
242
272
|
if (!this.#db._pgbdb || !this.#db.opened) {
|
|
@@ -409,7 +439,7 @@ export class PgBoss extends EventEmitter {
|
|
|
409
439
|
return this.#contractor.schemaVersion();
|
|
410
440
|
}
|
|
411
441
|
detectSchemaDrift() {
|
|
412
|
-
return this.#contractor.detectDrift();
|
|
442
|
+
return this.#contractor.detectDrift({ clockOverride: this.#attachedClock !== null });
|
|
413
443
|
}
|
|
414
444
|
/**
|
|
415
445
|
* Schedules a job on a recurring expression: a cron expression, or an RFC 5545 recurrence rule
|
|
@@ -450,4 +480,6 @@ export class PgBoss extends EventEmitter {
|
|
|
450
480
|
return new DbDefault(this.#config);
|
|
451
481
|
}
|
|
452
482
|
}
|
|
483
|
+
export { systemClock, TestClock } from "./clock.js";
|
|
484
|
+
export { CLOCK_OVERRIDE_SETTING, enableClockOverride, disableClockOverride } from "./plans.js";
|
|
453
485
|
export { fromKnex, fromKysely, fromDrizzle, fromPrisma, fromPglite, fromBunSql, } from "./adapters/index.js";
|
package/dist/manager.d.ts
CHANGED
|
@@ -19,8 +19,8 @@ declare class Manager extends EventEmitter implements types.EventsMixin {
|
|
|
19
19
|
wipTs: number;
|
|
20
20
|
workers: Map<string, Worker>;
|
|
21
21
|
stopped: boolean | undefined;
|
|
22
|
-
queueCacheInterval:
|
|
23
|
-
wipInterval:
|
|
22
|
+
queueCacheInterval: types.ClockTimer | undefined;
|
|
23
|
+
wipInterval: types.ClockTimer | undefined;
|
|
24
24
|
timekeeper: Timekeeper | undefined;
|
|
25
25
|
notifier: Notifier | undefined;
|
|
26
26
|
queues: Record<string, types.QueueResult> | null;
|
package/dist/manager.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../src/manager.ts"],"names":[],"mappings":"AAEA,OAAO,YAAY,MAAM,aAAa,CAAA;AAGtC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAA;AAE7B,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AAEzC,OAAO,KAAK,UAAU,MAAM,iBAAiB,CAAA;AAG7C,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,MAAM,MAAM,aAAa,CAAA;AAChC,OAAO,EAAU,KAAK,eAAe,EAAE,MAAM,UAAU,CAAA;AAiJvD,cAAM,OAAQ,SAAQ,YAAa,YAAW,KAAK,CAAC,WAAW;;IAC7D,MAAM;;;;MAAS;IAGf,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,GAAG;QAAE,MAAM,CAAC,EAAE,KAAK,CAAA;KAAE,CAAC,GAAG,EAAE,CAAA;IAC/C,MAAM,EAAE,KAAK,CAAC,0BAA0B,CAAA;IACxC,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC5B,OAAO,EAAE,OAAO,GAAG,SAAS,CAAA;IAC5B,kBAAkB,EAAE,
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../src/manager.ts"],"names":[],"mappings":"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"}
|