pg-boss 12.32.0 → 12.33.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/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.js +2 -2
- package/dist/boss.d.ts.map +1 -1
- package/dist/boss.js +5 -4
- 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.js +2 -2
- package/dist/plans.d.ts +17 -2
- package/dist/plans.d.ts.map +1 -1
- package/dist/plans.js +189 -83
- package/dist/schema.json +11 -3
- package/dist/timekeeper.d.ts.map +1 -1
- package/dist/timekeeper.js +10 -10
- 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/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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"}
|
package/dist/manager.js
CHANGED
|
@@ -168,7 +168,7 @@ class Manager extends EventEmitter {
|
|
|
168
168
|
super();
|
|
169
169
|
this.config = config;
|
|
170
170
|
this.db = db;
|
|
171
|
-
this.wipTs =
|
|
171
|
+
this.wipTs = config.clock.now();
|
|
172
172
|
this.workers = new Map();
|
|
173
173
|
this.queues = {};
|
|
174
174
|
this.pendingOffWorkCleanups = new Set();
|
|
@@ -503,7 +503,7 @@ class Manager extends EventEmitter {
|
|
|
503
503
|
if (heartbeatSeconds > 0) {
|
|
504
504
|
const refreshSeconds = heartbeatRefreshSeconds ?? (heartbeatSeconds / 2);
|
|
505
505
|
const intervalMs = refreshSeconds * 1000;
|
|
506
|
-
heartbeatTimer = setInterval(async () => {
|
|
506
|
+
heartbeatTimer = this.config.clock.setInterval(async () => {
|
|
507
507
|
try {
|
|
508
508
|
await this.touch(name, jobIds);
|
|
509
509
|
}
|
|
@@ -544,7 +544,7 @@ class Manager extends EventEmitter {
|
|
|
544
544
|
const handling = transaction
|
|
545
545
|
? callback(jobs, transaction.db)
|
|
546
546
|
: callback(jobs);
|
|
547
|
-
const result = await resolveWithinSeconds(handling, maxExpiration, `handler execution exceeded ${maxExpiration}s`, ac);
|
|
547
|
+
const result = await resolveWithinSeconds(this.config.clock, handling, maxExpiration, `handler execution exceeded ${maxExpiration}s`, ac);
|
|
548
548
|
// An abort resolves the race rather than rejecting it, so on this line an abandoned handler
|
|
549
549
|
// looks exactly like one that returned. failWip() aborts after failing the batch, so
|
|
550
550
|
// committing here would leave whatever the handler had written by then in the database
|
|
@@ -596,7 +596,7 @@ class Manager extends EventEmitter {
|
|
|
596
596
|
}
|
|
597
597
|
finally {
|
|
598
598
|
if (heartbeatTimer)
|
|
599
|
-
clearInterval(heartbeatTimer);
|
|
599
|
+
this.config.clock.clearInterval(heartbeatTimer);
|
|
600
600
|
if (worker) {
|
|
601
601
|
// Clear between jobs
|
|
602
602
|
worker.abortController = null;
|
|
@@ -750,9 +750,9 @@ class Manager extends EventEmitter {
|
|
|
750
750
|
}
|
|
751
751
|
async start() {
|
|
752
752
|
this.stopped = false;
|
|
753
|
-
this.queueCacheInterval = setInterval(() => this.onCacheQueues({ emit: true }), this.config.queueCacheIntervalSeconds * 1000);
|
|
754
|
-
this.wipInterval = setInterval(() => {
|
|
755
|
-
const now =
|
|
753
|
+
this.queueCacheInterval = this.config.clock.setInterval(() => this.onCacheQueues({ emit: true }), this.config.queueCacheIntervalSeconds * 1000);
|
|
754
|
+
this.wipInterval = this.config.clock.setInterval(() => {
|
|
755
|
+
const now = this.config.clock.now();
|
|
756
756
|
if ((now - this.wipTs) < 2000) {
|
|
757
757
|
return;
|
|
758
758
|
}
|
|
@@ -793,8 +793,8 @@ class Manager extends EventEmitter {
|
|
|
793
793
|
}
|
|
794
794
|
async stop() {
|
|
795
795
|
this.stopped = true;
|
|
796
|
-
clearInterval(this.queueCacheInterval);
|
|
797
|
-
clearInterval(this.wipInterval);
|
|
796
|
+
this.config.clock.clearInterval(this.queueCacheInterval);
|
|
797
|
+
this.config.clock.clearInterval(this.wipInterval);
|
|
798
798
|
await Promise.allSettled([...this.workers.values()]
|
|
799
799
|
.filter(worker => !INTERNAL_QUEUES[worker.name])
|
|
800
800
|
.map(async (worker) => await this.offWork(worker.name, { wait: false })));
|
|
@@ -912,7 +912,7 @@ class Manager extends EventEmitter {
|
|
|
912
912
|
const onError = (error) => {
|
|
913
913
|
this.emit(events.error, { ...error, message: error.message, stack: error.stack, queue: name, worker: workerId });
|
|
914
914
|
};
|
|
915
|
-
return new Worker({ id: workerId, workId, name, options, resolveInterval, fetch, onFetch, onError });
|
|
915
|
+
return new Worker({ id: workerId, workId, name, options, resolveInterval, fetch, onFetch, onError, clock: this.config.clock });
|
|
916
916
|
};
|
|
917
917
|
// Spawn workers based on localConcurrency setting
|
|
918
918
|
for (let i = 0; i < localConcurrency; i++) {
|
|
@@ -986,7 +986,7 @@ class Manager extends EventEmitter {
|
|
|
986
986
|
}
|
|
987
987
|
emitWip(name) {
|
|
988
988
|
if (!INTERNAL_QUEUES[name]) {
|
|
989
|
-
const now =
|
|
989
|
+
const now = this.config.clock.now();
|
|
990
990
|
if (now - this.wipTs > 2000) {
|
|
991
991
|
this.emit(events.wip, this.getWipData());
|
|
992
992
|
this.wipTs = now;
|
|
@@ -1442,7 +1442,7 @@ class Manager extends EventEmitter {
|
|
|
1442
1442
|
}
|
|
1443
1443
|
getDebounceStartAfter(singletonSeconds, clockOffset) {
|
|
1444
1444
|
const debounceInterval = singletonSeconds * 1000;
|
|
1445
|
-
const now =
|
|
1445
|
+
const now = this.config.clock.now() + clockOffset;
|
|
1446
1446
|
const slot = Math.floor(now / debounceInterval) * debounceInterval;
|
|
1447
1447
|
// prevent startAfter=0 during debouncing
|
|
1448
1448
|
let startAfter = (singletonSeconds - Math.floor((now - slot) / 1000)) || 1;
|
|
@@ -1688,7 +1688,7 @@ class Manager extends EventEmitter {
|
|
|
1688
1688
|
// Calculate start_after for retry
|
|
1689
1689
|
let startAfter = job.start_after;
|
|
1690
1690
|
if (!job.retry_backoff) {
|
|
1691
|
-
startAfter = new Date(
|
|
1691
|
+
startAfter = new Date(this.config.clock.now() + retryDelay * 1000);
|
|
1692
1692
|
}
|
|
1693
1693
|
else {
|
|
1694
1694
|
const exp = Math.min(16, retryCount + 1);
|
|
@@ -1696,7 +1696,7 @@ class Manager extends EventEmitter {
|
|
|
1696
1696
|
// Match the canonical failJobs() SQL: LEAST(retry_delay_max, delay) caps the backoff,
|
|
1697
1697
|
// treating NULL as "no cap" and 0 as a real cap. (`?:` would wrongly treat 0 as no cap.)
|
|
1698
1698
|
const cappedDelay = retryDelayMax != null ? Math.min(retryDelayMax, delay) : delay;
|
|
1699
|
-
startAfter = new Date(
|
|
1699
|
+
startAfter = new Date(this.config.clock.now() + cappedDelay * 1000);
|
|
1700
1700
|
}
|
|
1701
1701
|
// heartbeat_on resets to NULL on re-insert; heartbeat_seconds/blocked/blocking/
|
|
1702
1702
|
// pending_dependencies are preserved so flows and heartbeat detection survive a retry
|
|
@@ -1719,7 +1719,7 @@ class Manager extends EventEmitter {
|
|
|
1719
1719
|
job.id, job.name, job.priority, job.data, 'failed', job.retry_limit, job.retry_count,
|
|
1720
1720
|
job.retry_delay, job.retry_backoff, job.retry_delay_max, job.start_after, job.started_on,
|
|
1721
1721
|
job.singleton_key, job.singleton_on, job.group_id, job.group_tier, job.expire_seconds,
|
|
1722
|
-
job.deletion_seconds, job.created_on, new Date(), job.keep_until, job.policy,
|
|
1722
|
+
job.deletion_seconds, job.created_on, new Date(this.config.clock.now()), job.keep_until, job.policy,
|
|
1723
1723
|
jobOutput, job.dead_letter,
|
|
1724
1724
|
null, job.heartbeat_seconds, job.blocked, job.blocking, job.pending_dependencies
|
|
1725
1725
|
]);
|
|
@@ -1940,7 +1940,7 @@ class Manager extends EventEmitter {
|
|
|
1940
1940
|
activeCount: 0,
|
|
1941
1941
|
failedCount: 0,
|
|
1942
1942
|
totalCount: 0,
|
|
1943
|
-
capturedOn: row?.capturedOn ?? new Date()
|
|
1943
|
+
capturedOn: row?.capturedOn ?? new Date(this.config.clock.now())
|
|
1944
1944
|
};
|
|
1945
1945
|
for (const field of STATS_COUNT_FIELDS) {
|
|
1946
1946
|
const value = row?.[field];
|
|
@@ -1987,7 +1987,7 @@ class Manager extends EventEmitter {
|
|
|
1987
1987
|
: Math.max(QUEUE_STATS_CACHE_TTL_SECONDS, this.config.monitorIntervalSeconds ?? 0, this.config.superviseIntervalSeconds ?? 0)) * 1000;
|
|
1988
1988
|
const cacheAgeMs = cached.capturedOn == null
|
|
1989
1989
|
? Infinity
|
|
1990
|
-
:
|
|
1990
|
+
: this.config.clock.now() - new Date(cached.capturedOn).getTime();
|
|
1991
1991
|
// The vacuum-safety backoff outranks staleness, including a caller's { force: true }. Refreshing
|
|
1992
1992
|
// here runs the same whole-job-table aggregate the supervisor just backed away from, and a
|
|
1993
1993
|
// dashboard polling forced reads is exactly the "continuously running analytical query" shape
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrationStore.d.ts","sourceRoot":"","sources":["../src/migrationStore.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"migrationStore.d.ts","sourceRoot":"","sources":["../src/migrationStore.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AAKnC,UAAU,cAAc;IACtB,WAAW,CAAC,EAAE,OAAO,CAAA;IAKrB,eAAe,CAAC,EAAE,KAAK,CAAC,kBAAkB,EAAE,CAAA;CAC7C;AAoGD,UAAU,iBAAiB;IACzB,GAAG,EAAE,MAAM,CAAA;IACX,UAAU,EAAE,MAAM,EAAE,CAAA;CACrB;AASD,iBAAS,QAAQ,CAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,EAAE,EAAE,eAAe,CAAC,EAAE,OAAO,UAsB5G;AAED,iBAAS,IAAI,CAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,EAAE,EAAE,eAAe,CAAC,EAAE,OAAO,UAQxG;AAKD,iBAAS,eAAe,CAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,EAAE,EAAE,eAAe,CAAC,EAAE,OAAO,EAAE,OAAO,GAAE,cAAmB,GAAG,iBAAiB,CAiDrK;AAKD,iBAAS,OAAO,CAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,EAAE,EAAE,eAAe,CAAC,EAAE,OAAO,EAAE,OAAO,GAAE,cAAmB,UAIzI;AAoiCD,iBAAS,aAAa,CAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE9C;AAID,iBAAS,eAAe,CAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,0BAA0B,EAAE,QAAQ,GAAG,qBAAqB,GAAG,mBAAmB,GAAG,qBAAqB,CAAC,GAAG,KAAK,CAAC,SAAS,EAAE,CAE3K;AAOD,iBAAS,MAAM,CAAE,MAAM,EAAE,MAAM,EAAE,cAAc,UAAQ,EAAE,UAAU,UAAQ,EAAE,mBAAmB,UAAQ,GAAG,KAAK,CAAC,SAAS,EAAE,CAqkB3H;AAED,OAAO,EACL,QAAQ,EACR,IAAI,EACJ,OAAO,EACP,eAAe,EACf,MAAM,EACN,eAAe,EACf,aAAa,GACd,CAAA"}
|