@zukhruf/sqlite-queue 0.0.0-stage → 0.3.42
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 +151 -2
- package/dist/activity.d.ts +10 -0
- package/dist/activity.d.ts.map +1 -0
- package/dist/activity.js +93 -0
- package/dist/activity.js.map +1 -0
- package/dist/attorney.d.ts +35 -0
- package/dist/attorney.d.ts.map +1 -0
- package/dist/attorney.js +367 -0
- package/dist/attorney.js.map +1 -0
- package/dist/claim-timer.d.ts +8 -0
- package/dist/claim-timer.d.ts.map +1 -0
- package/dist/claim-timer.js +80 -0
- package/dist/claim-timer.js.map +1 -0
- package/dist/completion-data.d.ts +6 -0
- package/dist/completion-data.d.ts.map +1 -0
- package/dist/completion-data.js +36 -0
- package/dist/completion-data.js.map +1 -0
- package/dist/database-error.d.ts +6 -0
- package/dist/database-error.d.ts.map +1 -0
- package/dist/database-error.js +12 -0
- package/dist/database-error.js.map +1 -0
- package/dist/database.d.ts +7 -0
- package/dist/database.d.ts.map +1 -0
- package/dist/database.js +28 -0
- package/dist/database.js.map +1 -0
- package/dist/in-flight.d.ts +7 -0
- package/dist/in-flight.d.ts.map +1 -0
- package/dist/in-flight.js +24 -0
- package/dist/in-flight.js.map +1 -0
- package/dist/index.d.ts +54 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1069 -0
- package/dist/index.js.map +1 -0
- package/dist/job-fetcher.d.ts +16 -0
- package/dist/job-fetcher.d.ts.map +1 -0
- package/dist/job-fetcher.js +227 -0
- package/dist/job-fetcher.js.map +1 -0
- package/dist/job-queue.d.ts +27 -0
- package/dist/job-queue.d.ts.map +1 -0
- package/dist/job-queue.js +2 -0
- package/dist/job-queue.js.map +1 -0
- package/dist/job-rows.d.ts +49 -0
- package/dist/job-rows.d.ts.map +1 -0
- package/dist/job-rows.js +155 -0
- package/dist/job-rows.js.map +1 -0
- package/dist/job-settler.d.ts +24 -0
- package/dist/job-settler.d.ts.map +1 -0
- package/dist/job-settler.js +240 -0
- package/dist/job-settler.js.map +1 -0
- package/dist/jsonb.d.ts +7 -0
- package/dist/jsonb.d.ts.map +1 -0
- package/dist/jsonb.js +85 -0
- package/dist/jsonb.js.map +1 -0
- package/dist/local-groups.d.ts +16 -0
- package/dist/local-groups.d.ts.map +1 -0
- package/dist/local-groups.js +113 -0
- package/dist/local-groups.js.map +1 -0
- package/dist/naive-timestamp.d.ts +6 -0
- package/dist/naive-timestamp.d.ts.map +1 -0
- package/dist/naive-timestamp.js +21 -0
- package/dist/naive-timestamp.js.map +1 -0
- package/dist/queue-cache.d.ts +9 -0
- package/dist/queue-cache.d.ts.map +1 -0
- package/dist/queue-cache.js +27 -0
- package/dist/queue-cache.js.map +1 -0
- package/dist/queue-rows.d.ts +25 -0
- package/dist/queue-rows.d.ts.map +1 -0
- package/dist/queue-rows.js +44 -0
- package/dist/queue-rows.js.map +1 -0
- package/dist/recurrence.d.ts +11 -0
- package/dist/recurrence.d.ts.map +1 -0
- package/dist/recurrence.js +226 -0
- package/dist/recurrence.js.map +1 -0
- package/dist/rows.d.ts +10 -0
- package/dist/rows.d.ts.map +1 -0
- package/dist/rows.js +46 -0
- package/dist/rows.js.map +1 -0
- package/dist/schema.d.ts +3 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +139 -0
- package/dist/schema.js.map +1 -0
- package/dist/sql-values.d.ts +9 -0
- package/dist/sql-values.d.ts.map +1 -0
- package/dist/sql-values.js +26 -0
- package/dist/sql-values.js.map +1 -0
- package/dist/start-after.d.ts +10 -0
- package/dist/start-after.d.ts.map +1 -0
- package/dist/start-after.js +125 -0
- package/dist/start-after.js.map +1 -0
- package/dist/supervisor.d.ts +16 -0
- package/dist/supervisor.d.ts.map +1 -0
- package/dist/supervisor.js +288 -0
- package/dist/supervisor.js.map +1 -0
- package/dist/throttle.d.ts +6 -0
- package/dist/throttle.d.ts.map +1 -0
- package/dist/throttle.js +35 -0
- package/dist/throttle.js.map +1 -0
- package/dist/timekeeper.d.ts +36 -0
- package/dist/timekeeper.d.ts.map +1 -0
- package/dist/timekeeper.js +305 -0
- package/dist/timekeeper.js.map +1 -0
- package/dist/timers.d.ts +9 -0
- package/dist/timers.d.ts.map +1 -0
- package/dist/timers.js +50 -0
- package/dist/timers.js.map +1 -0
- package/dist/uuid.d.ts +7 -0
- package/dist/uuid.d.ts.map +1 -0
- package/dist/uuid.js +36 -0
- package/dist/uuid.js.map +1 -0
- package/dist/worker.d.ts +35 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +147 -0
- package/dist/worker.js.map +1 -0
- package/package.json +53 -4
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// A startAfter string pg-boss would hand to Postgres's own timestamp or
|
|
2
|
+
// interval grammar, outside the subset this queue resolves itself.
|
|
3
|
+
export class UnsupportedStartAfterError extends Error {
|
|
4
|
+
name = 'UnsupportedStartAfterError';
|
|
5
|
+
startAfter;
|
|
6
|
+
constructor(startAfter) {
|
|
7
|
+
super(`startAfter "${startAfter}" is outside the supported forms: a Date, seconds, an ISO 8601 date time or duration, or Postgres interval units with integer amounts`);
|
|
8
|
+
this.startAfter = startAfter;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
// pg-boss normalizes startAfter in Attorney.checkSendArgs
|
|
12
|
+
// (node_modules/pg-boss/dist/attorney.js:108-116, 140-146), then casts a
|
|
13
|
+
// date time string as timestamptz and anything else as an interval added to
|
|
14
|
+
// now (plans.js:2228-2230, 2299-2302). This resolves the same normalization
|
|
15
|
+
// and a cited subset of what Postgres then parses; every supported form is
|
|
16
|
+
// proven equal to pg-boss in the parity suite (src/parity).
|
|
17
|
+
export class StartAfter {
|
|
18
|
+
static #isoDate = /^\d{4}-\d{2}-\d{2}/;
|
|
19
|
+
static #zonelessTime = /^(?:[T ]\d{2}(?::\d{2}(?::\d{2}(?:[.,]\d+)?)?)?)?$/;
|
|
20
|
+
static #dateTime = /^(\d{4}-\d{2}-\d{2})(?:[T ](\d{2}):(\d{2})(?::(\d{2})(?:\.(\d+))?)?)?(Z|[+-]\d{2}(?::?\d{2})?)$/;
|
|
21
|
+
static #seconds = /^[+-]?\d+(?:\.\d+)?$/;
|
|
22
|
+
static #isoDuration = /^P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)W)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?)?$/;
|
|
23
|
+
static #unitsShape = /^(?:\d+\s*[a-z]+\s*)+$/i;
|
|
24
|
+
static #unitPairs = /(\d+)\s*([a-z]+)/gi;
|
|
25
|
+
// Postgres interval units with integer amounts, as the field they add to.
|
|
26
|
+
static #unitScales = new Map([
|
|
27
|
+
...['second', 'seconds', 'sec', 'secs'].map((unit) => [unit, { field: 'milliseconds', size: 1000 }]),
|
|
28
|
+
...['minute', 'minutes', 'min', 'mins'].map((unit) => [unit, { field: 'milliseconds', size: 60_000 }]),
|
|
29
|
+
...['hour', 'hours', 'hr', 'hrs'].map((unit) => [unit, { field: 'milliseconds', size: 3_600_000 }]),
|
|
30
|
+
...['day', 'days'].map((unit) => [unit, { field: 'days', size: 1 }]),
|
|
31
|
+
...['week', 'weeks'].map((unit) => [unit, { field: 'days', size: 7 }]),
|
|
32
|
+
...['month', 'months', 'mon', 'mons'].map((unit) => [unit, { field: 'months', size: 1 }]),
|
|
33
|
+
...['year', 'years', 'yr', 'yrs'].map((unit) => [unit, { field: 'months', size: 12 }]),
|
|
34
|
+
]);
|
|
35
|
+
static resolve(value, now) {
|
|
36
|
+
const normalized = StartAfter.#normalize(value);
|
|
37
|
+
if (normalized === undefined) {
|
|
38
|
+
return now;
|
|
39
|
+
}
|
|
40
|
+
// Errors name the caller's own value, not its normalized form.
|
|
41
|
+
const original = typeof value === 'string' ? value : normalized;
|
|
42
|
+
// plans.js:2228-2230: a string ending in Z or starting with a date is a
|
|
43
|
+
// timestamp, anything else an interval.
|
|
44
|
+
if (normalized.endsWith('Z') || StartAfter.#isoDate.test(normalized)) {
|
|
45
|
+
return StartAfter.#timestamp(normalized, original);
|
|
46
|
+
}
|
|
47
|
+
return StartAfter.#add(now, StartAfter.#interval(normalized, original));
|
|
48
|
+
}
|
|
49
|
+
// attorney.js:140-146
|
|
50
|
+
static #normalize(value) {
|
|
51
|
+
if (value instanceof Date) {
|
|
52
|
+
return value.toISOString();
|
|
53
|
+
}
|
|
54
|
+
if (Number(value) > 0) {
|
|
55
|
+
return String(value);
|
|
56
|
+
}
|
|
57
|
+
if (typeof value === 'string') {
|
|
58
|
+
// attorney.js:115-117, pinZonelessDateTime.
|
|
59
|
+
return StartAfter.#isoDate.test(value) &&
|
|
60
|
+
StartAfter.#zonelessTime.test(value.slice(10))
|
|
61
|
+
? `${value}Z`
|
|
62
|
+
: value;
|
|
63
|
+
}
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
static #timestamp(value, original) {
|
|
67
|
+
const match = StartAfter.#dateTime.exec(value);
|
|
68
|
+
if (!match) {
|
|
69
|
+
throw new UnsupportedStartAfterError(original);
|
|
70
|
+
}
|
|
71
|
+
const [, date, hour = '00', minute = '00', second = '00', fraction, zone] = match;
|
|
72
|
+
const offset = zone === undefined || zone === 'Z'
|
|
73
|
+
? 'Z'
|
|
74
|
+
: `${zone.slice(0, 3)}:${zone.slice(3).replace(':', '') || '00'}`;
|
|
75
|
+
const milliseconds = fraction === undefined ? '' : `.${fraction}`;
|
|
76
|
+
return new Date(`${date}T${hour}:${minute}:${second}${milliseconds}${offset}`);
|
|
77
|
+
}
|
|
78
|
+
static #interval(value, original) {
|
|
79
|
+
const trimmed = value.trim();
|
|
80
|
+
if (StartAfter.#seconds.test(trimmed)) {
|
|
81
|
+
return { months: 0, days: 0, milliseconds: Number(trimmed) * 1000 };
|
|
82
|
+
}
|
|
83
|
+
const duration = StartAfter.#isoDuration.exec(trimmed);
|
|
84
|
+
if (duration && trimmed !== 'P' && !trimmed.endsWith('T')) {
|
|
85
|
+
const [, years, months, weeks, days, hours, minutes, seconds] = duration;
|
|
86
|
+
return {
|
|
87
|
+
months: Number(years ?? 0) * 12 + Number(months ?? 0),
|
|
88
|
+
days: Number(weeks ?? 0) * 7 + Number(days ?? 0),
|
|
89
|
+
milliseconds: Number(hours ?? 0) * 3_600_000 +
|
|
90
|
+
Number(minutes ?? 0) * 60_000 +
|
|
91
|
+
Number(seconds ?? 0) * 1000,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
return StartAfter.#units(trimmed, original);
|
|
95
|
+
}
|
|
96
|
+
static #units(trimmed, original) {
|
|
97
|
+
if (!StartAfter.#unitsShape.test(trimmed)) {
|
|
98
|
+
throw new UnsupportedStartAfterError(original);
|
|
99
|
+
}
|
|
100
|
+
const interval = { months: 0, days: 0, milliseconds: 0 };
|
|
101
|
+
for (const [, amount, unit] of trimmed.matchAll(StartAfter.#unitPairs)) {
|
|
102
|
+
const scale = StartAfter.#unitScales.get(String(unit).toLowerCase());
|
|
103
|
+
if (scale === undefined) {
|
|
104
|
+
throw new UnsupportedStartAfterError(original);
|
|
105
|
+
}
|
|
106
|
+
interval[scale.field] += Number(amount) * scale.size;
|
|
107
|
+
}
|
|
108
|
+
return interval;
|
|
109
|
+
}
|
|
110
|
+
// Postgres adds an interval's months (clamped to the target month's last
|
|
111
|
+
// day), then its days, then its time part.
|
|
112
|
+
static #add(now, interval) {
|
|
113
|
+
const result = new Date(now.getTime());
|
|
114
|
+
if (interval.months !== 0) {
|
|
115
|
+
const day = result.getUTCDate();
|
|
116
|
+
result.setUTCDate(1);
|
|
117
|
+
result.setUTCMonth(result.getUTCMonth() + interval.months);
|
|
118
|
+
const lastDay = new Date(Date.UTC(result.getUTCFullYear(), result.getUTCMonth() + 1, 0)).getUTCDate();
|
|
119
|
+
result.setUTCDate(Math.min(day, lastDay));
|
|
120
|
+
}
|
|
121
|
+
result.setUTCDate(result.getUTCDate() + interval.days);
|
|
122
|
+
return new Date(result.getTime() + interval.milliseconds);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=start-after.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start-after.js","sourceRoot":"","sources":["../src/start-after.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
3
|
+
import type { Clock, PgBossEventMap } from 'pg-boss';
|
|
4
|
+
import type { Activity } from './activity.ts';
|
|
5
|
+
import type { SuperviseIntervals } from './attorney.ts';
|
|
6
|
+
export type SupervisorConfig = SuperviseIntervals & {
|
|
7
|
+
supervise: boolean | undefined;
|
|
8
|
+
warningQueueSize: number | undefined;
|
|
9
|
+
};
|
|
10
|
+
export declare class Supervisor extends EventEmitter<Pick<PgBossEventMap, 'error' | 'warning'>> {
|
|
11
|
+
#private;
|
|
12
|
+
constructor(clock: Clock, activity: Activity, config: SupervisorConfig);
|
|
13
|
+
start(database: DatabaseSync): void;
|
|
14
|
+
stop(): Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=supervisor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"supervisor.d.ts","sourceRoot":"","sources":["../src/supervisor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAKrD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AA4BxD,MAAM,MAAM,gBAAgB,GAAG,kBAAkB,GAAG;IAClD,SAAS,EAAE,OAAO,GAAG,SAAS,CAAC;IAC/B,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;CACtC,CAAC;AAoBF,qBAAa,UAAW,SAAQ,YAAY,CAC1C,IAAI,CAAC,cAAc,EAAE,OAAO,GAAG,SAAS,CAAC,CAC1C;;gBAUa,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,gBAAgB;IAUtE,KAAK,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI;IAa7B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAuU5B"}
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import assert from 'node:assert';
|
|
2
|
+
import { EventEmitter } from 'node:events';
|
|
3
|
+
import { policies } from 'pg-boss';
|
|
4
|
+
import { transaction } from '@zukhruf/sqlite-transaction';
|
|
5
|
+
import { ClaimTimer } from "./claim-timer.js";
|
|
6
|
+
import { InFlight } from "./in-flight.js";
|
|
7
|
+
import { JobSettler } from "./job-settler.js";
|
|
8
|
+
import { Row } from "./rows.js";
|
|
9
|
+
import { SqlValues } from "./sql-values.js";
|
|
10
|
+
// node_modules/pg-boss/dist/boss.js:14
|
|
11
|
+
const LARGE_QUEUE = { size: 10_000, message: 'Warning: large queue backlog' };
|
|
12
|
+
// The outputs failJobsByTimeout and failJobsByHeartbeat store (plans.js:2376,
|
|
13
|
+
// 2384).
|
|
14
|
+
const TIMED_OUT = JSON.stringify({ value: { message: 'job timed out' } });
|
|
15
|
+
const HEARTBEAT_TIMED_OUT = JSON.stringify({
|
|
16
|
+
value: { message: 'job heartbeat timeout' },
|
|
17
|
+
});
|
|
18
|
+
// A pass works on at most this many queues at a time (boss.js:269).
|
|
19
|
+
const CHUNK = 100;
|
|
20
|
+
// pg-boss's Boss (node_modules/pg-boss/dist/boss.js) for one job table: a
|
|
21
|
+
// pass every superviseIntervalSeconds claims each queue's monitor and
|
|
22
|
+
// maintenance when due, refreshes the monitored queues' counts, warns about
|
|
23
|
+
// backlogs and fails expired and heartbeat-lost jobs, then deletes what the
|
|
24
|
+
// maintained queues no longer keep. Each statement is one Activity.query, so
|
|
25
|
+
// an attached TestClock waits the whole pass out. The pass's Postgres tail
|
|
26
|
+
// (vacuum backoff and check, warning and stats retention, reindex) and
|
|
27
|
+
// cleanupDependencies (no job_dependency table) have no counterpart here.
|
|
28
|
+
export class Supervisor extends EventEmitter {
|
|
29
|
+
#clock;
|
|
30
|
+
#activity;
|
|
31
|
+
#config;
|
|
32
|
+
// boss.js:121
|
|
33
|
+
#largeQueueSize;
|
|
34
|
+
#phase = { kind: 'unstarted' };
|
|
35
|
+
// pg-boss's #maintaining: the pass in flight.
|
|
36
|
+
#pass = null;
|
|
37
|
+
constructor(clock, activity, config) {
|
|
38
|
+
super();
|
|
39
|
+
this.#clock = clock;
|
|
40
|
+
this.#activity = activity;
|
|
41
|
+
this.#config = config;
|
|
42
|
+
this.#largeQueueSize = config.warningQueueSize || LARGE_QUEUE.size;
|
|
43
|
+
}
|
|
44
|
+
// boss.js:128-137: started whether or not supervise is set, which only
|
|
45
|
+
// decides whether the timer is armed.
|
|
46
|
+
start(database) {
|
|
47
|
+
if (this.#phase.kind === 'supervising') {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const timer = this.#config.supervise
|
|
51
|
+
? new ClaimTimer(this.#clock, this.#config.superviseIntervalSeconds, () => this.#onSupervise())
|
|
52
|
+
: null;
|
|
53
|
+
this.#phase = { kind: 'supervising', database, timer };
|
|
54
|
+
}
|
|
55
|
+
// boss.js:138-148, which polls its pass flag every 10 ms of real time.
|
|
56
|
+
async stop() {
|
|
57
|
+
const phase = this.#phase;
|
|
58
|
+
if (phase.kind !== 'supervising') {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
phase.timer?.stop();
|
|
62
|
+
this.#phase = { kind: 'stopped', database: phase.database };
|
|
63
|
+
await this.#pass?.settled();
|
|
64
|
+
}
|
|
65
|
+
get #stopped() {
|
|
66
|
+
return this.#phase.kind !== 'supervising';
|
|
67
|
+
}
|
|
68
|
+
// boss.js:173-199
|
|
69
|
+
async #onSupervise() {
|
|
70
|
+
if (this.#stopped || this.#pass) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const pass = this.#supervise();
|
|
74
|
+
this.#pass = new InFlight(pass);
|
|
75
|
+
try {
|
|
76
|
+
await pass;
|
|
77
|
+
}
|
|
78
|
+
finally {
|
|
79
|
+
this.#pass = null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async #supervise() {
|
|
83
|
+
try {
|
|
84
|
+
const names = await this.#query((db) => Supervisor.#queueNames(db));
|
|
85
|
+
if (!this.#stopped) {
|
|
86
|
+
await this.#supervisePass(names);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
this.emit('error', error instanceof Error ? error : new Error(String(error)));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// boss.js:239-279: the next pass is anchored once every claim is stamped.
|
|
94
|
+
async #supervisePass(names) {
|
|
95
|
+
for (let start = 0; start < names.length; start += CHUNK) {
|
|
96
|
+
if (this.#stopped) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const chunk = names.slice(start, start + CHUNK);
|
|
100
|
+
await this.#monitor(chunk);
|
|
101
|
+
await this.#maintain(chunk);
|
|
102
|
+
}
|
|
103
|
+
if (this.#phase.kind === 'supervising') {
|
|
104
|
+
this.#phase.timer?.anchor();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// boss.js:293-381. Nothing here backs off the stats, so every claimed
|
|
108
|
+
// queue's counts are refreshed (refreshStats, plans.js:987).
|
|
109
|
+
async #monitor(names) {
|
|
110
|
+
if (this.#stopped) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const claimed = await this.#query((db, now) => Supervisor.#claim(db, names, 'monitor_claim_on', 'COALESCE(monitor_claim_on, monitor_on)', this.#config.monitorIntervalSeconds, now));
|
|
114
|
+
if (this.#stopped || claimed.length === 0) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const stats = await this.#query((db, now) => Supervisor.#cacheQueueStats(db, claimed, now));
|
|
118
|
+
if (this.#stopped) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
// boss.js:352-358
|
|
122
|
+
for (const row of stats) {
|
|
123
|
+
const threshold = row.warningQueueSize || this.#largeQueueSize;
|
|
124
|
+
if (row.queuedCount > threshold) {
|
|
125
|
+
this.emit('warning', {
|
|
126
|
+
message: `${LARGE_QUEUE.message}: queue "${row.name}" has ${row.queuedCount} jobs in the ` +
|
|
127
|
+
`created or retry state, over its warning threshold of ${threshold}. Your queue should be reviewed`,
|
|
128
|
+
data: row,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (this.#stopped) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const queues = JSON.stringify(claimed);
|
|
136
|
+
// failJobsByTimeout (plans.js:2372-2378)
|
|
137
|
+
await this.#query((db, now) => JobSettler.failJobs(db, [
|
|
138
|
+
`state = 'active'
|
|
139
|
+
AND ${SqlValues.plusSecondsSql('started_on', 'expire_seconds')} < ?
|
|
140
|
+
AND queue_name IN (SELECT value FROM json_each(?))`,
|
|
141
|
+
SqlValues.asIso(now),
|
|
142
|
+
queues,
|
|
143
|
+
], TIMED_OUT, now));
|
|
144
|
+
if (this.#stopped) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
// failJobsByHeartbeat (plans.js:2379-2386)
|
|
148
|
+
await this.#query((db, now) => JobSettler.failJobs(db, [
|
|
149
|
+
`state = 'active'
|
|
150
|
+
AND heartbeat_seconds IS NOT NULL
|
|
151
|
+
AND ${SqlValues.plusSecondsSql('heartbeat_on', 'heartbeat_seconds')} < ?
|
|
152
|
+
AND queue_name IN (SELECT value FROM json_each(?))`,
|
|
153
|
+
SqlValues.asIso(now),
|
|
154
|
+
queues,
|
|
155
|
+
], HEARTBEAT_TIMED_OUT, now));
|
|
156
|
+
}
|
|
157
|
+
// boss.js:382-396
|
|
158
|
+
async #maintain(names) {
|
|
159
|
+
if (this.#stopped) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const claimed = await this.#query((db, now) => Supervisor.#claim(db, names, 'maintain_on', 'maintain_on', this.#config.maintenanceIntervalSeconds, now));
|
|
163
|
+
if (this.#stopped) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
if (claimed.length > 0) {
|
|
167
|
+
await this.#query((db, now) => Supervisor.#deletion(db, claimed, now));
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// A statement on the clock's now, run when issued and settled one counted
|
|
171
|
+
// turn later.
|
|
172
|
+
#query(statement) {
|
|
173
|
+
return this.#activity.query(() => {
|
|
174
|
+
assert(this.#phase.kind !== 'unstarted', 'Database not opened.');
|
|
175
|
+
return statement(this.#phase.database, new Date(this.#clock.now()));
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
// getQueues (plans.js:1181-1220) has no ORDER BY; PGlite returns the
|
|
179
|
+
// queues in creation order, which decides each 100-queue chunk.
|
|
180
|
+
static #queueNames(db) {
|
|
181
|
+
return db
|
|
182
|
+
.prepare('SELECT name FROM pgboss_queue ORDER BY rowid')
|
|
183
|
+
.all()
|
|
184
|
+
.map((row) => Row.readString(row, 'name'));
|
|
185
|
+
}
|
|
186
|
+
// trySetQueueMonitorTime and trySetQueueTimestamp (plans.js:973-990,
|
|
187
|
+
// 1119-1137): a queue is due once its stamp is `seconds` old, or at once
|
|
188
|
+
// without one; the due queues are stamped now. pg-boss takes the rows in
|
|
189
|
+
// name order only as a lock order (queueRowLock, 1146-1148) and leaves its
|
|
190
|
+
// RETURNING order to the planner; SQLite's single writer needs no lock
|
|
191
|
+
// order, and name order keeps the pass's warnings in one stable order.
|
|
192
|
+
static #claim(db, names, column, stamp, seconds, now) {
|
|
193
|
+
return transaction(db, () => {
|
|
194
|
+
const due = db
|
|
195
|
+
.prepare(`SELECT name, ${stamp} AS stamp FROM pgboss_queue
|
|
196
|
+
WHERE name IN (SELECT value FROM json_each(?))
|
|
197
|
+
ORDER BY name`)
|
|
198
|
+
.all(JSON.stringify(names))
|
|
199
|
+
.filter((row) => {
|
|
200
|
+
const stamped = Row.readNullableString(row, 'stamp');
|
|
201
|
+
return (stamped === null ||
|
|
202
|
+
(now.getTime() - Date.parse(stamped)) / 1000 >= seconds);
|
|
203
|
+
})
|
|
204
|
+
.map((row) => Row.readString(row, 'name'));
|
|
205
|
+
const update = db.prepare(`UPDATE pgboss_queue SET ${column} = ? WHERE name = ?`);
|
|
206
|
+
for (const name of due) {
|
|
207
|
+
update.run(SqlValues.asIso(now), name);
|
|
208
|
+
}
|
|
209
|
+
return due;
|
|
210
|
+
}, { mode: 'immediate' });
|
|
211
|
+
}
|
|
212
|
+
// cacheQueueStats over getQueueStats (plans.js:3411-3471, 3480-3557): each
|
|
213
|
+
// claimed queue's counts by state, the keys its singleton and stately jobs
|
|
214
|
+
// hold active (NULL for none, as array_agg over no rows) and monitor_on,
|
|
215
|
+
// written and returned in the claim's order.
|
|
216
|
+
static #cacheQueueStats(db, names, now) {
|
|
217
|
+
const started = performance.now();
|
|
218
|
+
const isoNow = SqlValues.asIso(now);
|
|
219
|
+
const queues = JSON.stringify(names);
|
|
220
|
+
return transaction(db, () => {
|
|
221
|
+
const counts = new Map(db
|
|
222
|
+
.prepare(`SELECT queue_name,
|
|
223
|
+
SUM(state IN ('created', 'retry') AND start_after > ?) AS deferred,
|
|
224
|
+
SUM(state IN ('created', 'retry')) AS queued,
|
|
225
|
+
SUM(state = 'active') AS active,
|
|
226
|
+
SUM(state = 'failed') AS failed,
|
|
227
|
+
COUNT(*) AS total
|
|
228
|
+
FROM pgboss_job
|
|
229
|
+
WHERE queue_name IN (SELECT value FROM json_each(?))
|
|
230
|
+
GROUP BY queue_name`)
|
|
231
|
+
.all(isoNow, queues)
|
|
232
|
+
.map((row) => [Row.readString(row, 'queue_name'), row]));
|
|
233
|
+
const singletons = new Map();
|
|
234
|
+
for (const row of db
|
|
235
|
+
.prepare(`SELECT queue_name, singleton_key FROM pgboss_job
|
|
236
|
+
WHERE queue_name IN (SELECT value FROM json_each(?))
|
|
237
|
+
AND state = 'active'
|
|
238
|
+
AND policy IN ('${policies.singleton}', '${policies.stately}')
|
|
239
|
+
ORDER BY rowid`)
|
|
240
|
+
.all(queues)) {
|
|
241
|
+
const name = Row.readString(row, 'queue_name');
|
|
242
|
+
singletons.set(name, [
|
|
243
|
+
...(singletons.get(name) ?? []),
|
|
244
|
+
Row.readNullableString(row, 'singleton_key'),
|
|
245
|
+
]);
|
|
246
|
+
}
|
|
247
|
+
const update = db.prepare(`UPDATE pgboss_queue SET
|
|
248
|
+
deferred_count = ?,
|
|
249
|
+
queued_count = ?,
|
|
250
|
+
ready_count = ?,
|
|
251
|
+
active_count = ?,
|
|
252
|
+
failed_count = ?,
|
|
253
|
+
total_count = ?,
|
|
254
|
+
singletons_active = ?,
|
|
255
|
+
monitor_on = ?
|
|
256
|
+
WHERE name = ?
|
|
257
|
+
RETURNING name, queued_count, warning_queue_size`);
|
|
258
|
+
return names.flatMap((name) => {
|
|
259
|
+
const row = counts.get(name);
|
|
260
|
+
const count = (column) => row ? Row.readNumber(row, column) : 0;
|
|
261
|
+
const keys = singletons.get(name);
|
|
262
|
+
const written = update.get(count('deferred'), count('queued'), Math.max(count('queued') - count('deferred'), 0), count('active'), count('failed'), count('total'), keys ? JSON.stringify(keys) : null, isoNow, name);
|
|
263
|
+
return written === undefined
|
|
264
|
+
? []
|
|
265
|
+
: [
|
|
266
|
+
{
|
|
267
|
+
name: Row.readString(written, 'name'),
|
|
268
|
+
queuedCount: Row.readNumber(written, 'queued_count'),
|
|
269
|
+
warningQueueSize: Row.readNumber(written, 'warning_queue_size'),
|
|
270
|
+
pinSeconds: (performance.now() - started) / 1000,
|
|
271
|
+
},
|
|
272
|
+
];
|
|
273
|
+
});
|
|
274
|
+
}, { mode: 'immediate' });
|
|
275
|
+
}
|
|
276
|
+
// deletion (plans.js:3055-3066): settled jobs deletion_seconds after they
|
|
277
|
+
// settled, unless that is 0, and jobs never started once past keep_until.
|
|
278
|
+
static #deletion(db, names, now) {
|
|
279
|
+
const isoNow = SqlValues.asIso(now);
|
|
280
|
+
db.prepare(`DELETE FROM pgboss_job
|
|
281
|
+
WHERE queue_name IN (SELECT value FROM json_each(?))
|
|
282
|
+
AND (
|
|
283
|
+
(deletion_seconds > 0 AND ${SqlValues.plusSecondsSql('completed_on', 'deletion_seconds')} < ?)
|
|
284
|
+
OR (state IN ('created', 'retry') AND keep_until < ?)
|
|
285
|
+
)`).run(JSON.stringify(names), isoNow, isoNow);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
//# sourceMappingURL=supervisor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"supervisor.js","sourceRoot":"","sources":["../src/supervisor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { SendOptions } from 'pg-boss';
|
|
2
|
+
export declare class Throttle {
|
|
3
|
+
static slot(singletonSeconds: SendOptions['singletonSeconds'], offset: SendOptions['singletonSeconds'], now: Date): string | null;
|
|
4
|
+
static debounceStartAfter(singletonSeconds: SendOptions['singletonSeconds'], now: Date): number;
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=throttle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"throttle.d.ts","sourceRoot":"","sources":["../src/throttle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAO3C,qBAAa,QAAQ;IAOnB,MAAM,CAAC,IAAI,CACT,gBAAgB,EAAE,WAAW,CAAC,kBAAkB,CAAC,EACjD,MAAM,EAAE,WAAW,CAAC,kBAAkB,CAAC,EACvC,GAAG,EAAE,IAAI,GACR,MAAM,GAAG,IAAI;IAgBhB,MAAM,CAAC,kBAAkB,CACvB,gBAAgB,EAAE,WAAW,CAAC,kBAAkB,CAAC,EACjD,GAAG,EAAE,IAAI,GACR,MAAM;CAQV"}
|
package/dist/throttle.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { DatabaseError } from "./database-error.js";
|
|
2
|
+
import { NaiveTimestamp } from "./naive-timestamp.js";
|
|
3
|
+
// pg-boss's send throttle: singletonSeconds, and singletonNextSlot to retry a
|
|
4
|
+
// refused send into the next slot.
|
|
5
|
+
export class Throttle {
|
|
6
|
+
// pg-boss's throttle slot: singletonSeconds wide, shifted by an offset, as a
|
|
7
|
+
// zoneless timestamp (node_modules/pg-boss/dist/plans.js:2279). A null width
|
|
8
|
+
// is no throttle there (`"singletonSeconds" IS NOT NULL`), and a zero width
|
|
9
|
+
// divides by zero in Postgres, which pg-boss surfaces as the driver's error.
|
|
10
|
+
// The offset is 0, or singletonSeconds when a refused send retries into the
|
|
11
|
+
// next slot (manager.js:1253-1256).
|
|
12
|
+
static slot(singletonSeconds, offset, now) {
|
|
13
|
+
if (singletonSeconds === undefined || singletonSeconds === null) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
const width = Number(singletonSeconds);
|
|
17
|
+
if (width === 0) {
|
|
18
|
+
throw new DatabaseError('division by zero', '22012');
|
|
19
|
+
}
|
|
20
|
+
const slotStartSeconds = width * Math.floor((now.getTime() / 1000 + Number(offset)) / width);
|
|
21
|
+
return NaiveTimestamp.fromUtc(new Date(slotStartSeconds * 1000));
|
|
22
|
+
}
|
|
23
|
+
// manager.js:1533-1542: seconds until the next throttle slot starts, never 0,
|
|
24
|
+
// and one more for slots wider than a second. Without a width the slot
|
|
25
|
+
// arithmetic is NaN, which the `|| 1` floors, as in pg-boss.
|
|
26
|
+
static debounceStartAfter(singletonSeconds, now) {
|
|
27
|
+
const width = Number(singletonSeconds);
|
|
28
|
+
const interval = width * 1000;
|
|
29
|
+
const slotStart = Math.floor(now.getTime() / interval) * interval;
|
|
30
|
+
const elapsedSeconds = Math.floor((now.getTime() - slotStart) / 1000);
|
|
31
|
+
const startAfter = width - elapsedSeconds || 1;
|
|
32
|
+
return width > 1 ? startAfter + 1 : startAfter;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=throttle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"throttle.js","sourceRoot":"","sources":["../src/throttle.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,8EAA8E;AAC9E,mCAAmC;AACnC,MAAM,OAAO,QAAQ;IACnB,6EAA6E;IAC7E,6EAA6E;IAC7E,4EAA4E;IAC5E,6EAA6E;IAC7E,4EAA4E;IAC5E,oCAAoC;IACpC,MAAM,CAAC,IAAI,CACT,gBAAiD,EACjD,MAAuC,EACvC,GAAS;QAET,IAAI,gBAAgB,KAAK,SAAS,IAAI,gBAAgB,KAAK,IAAI,EAAE,CAAC;YAChE,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC;QACvC,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;YAChB,MAAM,IAAI,aAAa,CAAC,kBAAkB,EAAE,OAAO,CAAC,CAAC;QACvD,CAAC;QACD,MAAM,gBAAgB,GACpB,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC;QACtE,OAAO,cAAc,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC,CAAC;IACnE,CAAC;IAED,8EAA8E;IAC9E,uEAAuE;IACvE,6DAA6D;IAC7D,MAAM,CAAC,kBAAkB,CACvB,gBAAiD,EACjD,GAAS;QAET,MAAM,KAAK,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC;QACvC,MAAM,QAAQ,GAAG,KAAK,GAAG,IAAI,CAAC;QAC9B,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,QAAQ,CAAC,GAAG,QAAQ,CAAC;QAClE,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,SAAS,CAAC,GAAG,IAAI,CAAC,CAAC;QACtE,MAAM,UAAU,GAAG,KAAK,GAAG,cAAc,IAAI,CAAC,CAAC;QAC/C,OAAO,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;IACjD,CAAC;CACF"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
3
|
+
import type { Clock, PgBossEventMap, WorkHandler, WorkOptions } from 'pg-boss';
|
|
4
|
+
import type { Activity } from './activity.ts';
|
|
5
|
+
export type SlottedJob = {
|
|
6
|
+
data: {
|
|
7
|
+
name: string;
|
|
8
|
+
key: string;
|
|
9
|
+
data: unknown;
|
|
10
|
+
options: unknown;
|
|
11
|
+
slot: string;
|
|
12
|
+
};
|
|
13
|
+
singletonKey: string;
|
|
14
|
+
singletonOn: string;
|
|
15
|
+
};
|
|
16
|
+
export type TimekeeperManager = {
|
|
17
|
+
createQueue(name: string): Promise<void>;
|
|
18
|
+
work(name: string, options: WorkOptions, handler: WorkHandler<unknown>): Promise<string>;
|
|
19
|
+
offWork(name: string, options: {
|
|
20
|
+
wait: boolean;
|
|
21
|
+
}): Promise<void>;
|
|
22
|
+
send(request: unknown): Promise<string | null>;
|
|
23
|
+
insert(name: string, jobs: SlottedJob[]): Promise<void>;
|
|
24
|
+
};
|
|
25
|
+
export type TimekeeperConfig = {
|
|
26
|
+
cronMonitorIntervalSeconds: number;
|
|
27
|
+
cronWorkerIntervalSeconds: number;
|
|
28
|
+
};
|
|
29
|
+
export declare class Timekeeper extends EventEmitter<Pick<PgBossEventMap, 'error'>> {
|
|
30
|
+
#private;
|
|
31
|
+
static readonly sendIt = "__pgboss__send-it";
|
|
32
|
+
constructor(clock: Clock, activity: Activity, config: TimekeeperConfig, manager: TimekeeperManager);
|
|
33
|
+
start(database: DatabaseSync): Promise<void>;
|
|
34
|
+
stop(): Promise<void>;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=timekeeper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timekeeper.d.ts","sourceRoot":"","sources":["../src/timekeeper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAIhD,OAAO,KAAK,EACV,KAAK,EAEL,cAAc,EACd,WAAW,EACX,WAAW,EACZ,MAAM,SAAS,CAAC;AAKjB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAW9C,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM,CAAC;QACb,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,OAAO,CAAC;QACd,OAAO,EAAE,OAAO,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAIF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,IAAI,CACF,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC,GAC5B,OAAO,CAAC,MAAM,CAAC,CAAC;IACnB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjE,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC/C,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACzD,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,0BAA0B,EAAE,MAAM,CAAC;IACnC,yBAAyB,EAAE,MAAM,CAAC;CACnC,CAAC;AAgCF,qBAAa,UAAW,SAAQ,YAAY,CAAC,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;;IAEzE,MAAM,CAAC,QAAQ,CAAC,MAAM,uBAAuB;gBAkB3C,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,gBAAgB,EACxB,OAAO,EAAE,iBAAiB;IA+CtB,KAAK,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IA2B5C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CA4R5B"}
|