@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,24 @@
|
|
|
1
|
+
import type { DatabaseSync, SQLInputValue } from 'node:sqlite';
|
|
2
|
+
import { type JobAttempt } from 'pg-boss';
|
|
3
|
+
import type { JobRow } from './job-rows.ts';
|
|
4
|
+
export type JobOutcome = JobAttempt & {
|
|
5
|
+
output: unknown;
|
|
6
|
+
};
|
|
7
|
+
export declare class JobSettler {
|
|
8
|
+
#private;
|
|
9
|
+
static response(ids: string[], settled: string[]): {
|
|
10
|
+
jobs: string[];
|
|
11
|
+
requested: number;
|
|
12
|
+
affected: number;
|
|
13
|
+
settled: string[];
|
|
14
|
+
};
|
|
15
|
+
static complete(db: DatabaseSync, name: string, ids: string[], attempts: number[], data: unknown, now: Date): void;
|
|
16
|
+
static completeWithOutputs(db: DatabaseSync, name: string, outcomes: JobOutcome[], now: Date): void;
|
|
17
|
+
static fail(db: DatabaseSync, name: string, ids: string[], data: unknown, attempts: number[] | undefined, now: Date): string[];
|
|
18
|
+
static failJobs(db: DatabaseSync, [where, ...values]: [sql: string, ...values: SQLInputValue[]], output: string, now: Date): void;
|
|
19
|
+
static failWithOutputs(db: DatabaseSync, name: string, outcomes: JobOutcome[], forceTerminal: boolean, now: Date): void;
|
|
20
|
+
static cancel(db: DatabaseSync, name: string, ids: string[], attempts: number[] | undefined, now: Date): string[];
|
|
21
|
+
static restore(db: DatabaseSync, name: string, ids: string[]): void;
|
|
22
|
+
static touch(db: DatabaseSync, name: string, held: JobRow[], now: Date): Set<string>;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=job-settler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"job-settler.d.ts","sourceRoot":"","sources":["../src/job-settler.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE/D,OAAO,EAAE,KAAK,UAAU,EAAY,MAAM,SAAS,CAAC;AAQpD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAa5C,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,CAAC;AAQ1D,qBAAa,UAAU;;IAIrB,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE;;;;;;IAShD,MAAM,CAAC,QAAQ,CACb,EAAE,EAAE,YAAY,EAChB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EAAE,EACb,QAAQ,EAAE,MAAM,EAAE,EAClB,IAAI,EAAE,OAAO,EACb,GAAG,EAAE,IAAI,GACR,IAAI;IAYP,MAAM,CAAC,mBAAmB,CACxB,EAAE,EAAE,YAAY,EAChB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,UAAU,EAAE,EACtB,GAAG,EAAE,IAAI,GACR,IAAI;IAmCP,MAAM,CAAC,IAAI,CACT,EAAE,EAAE,YAAY,EAChB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EAAE,EACb,IAAI,EAAE,OAAO,EACb,QAAQ,EAAE,MAAM,EAAE,GAAG,SAAS,EAC9B,GAAG,EAAE,IAAI,GACR,MAAM,EAAE;IAgBX,MAAM,CAAC,QAAQ,CACb,EAAE,EAAE,YAAY,EAChB,CAAC,KAAK,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,aAAa,EAAE,CAAC,EAC7D,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,IAAI,GACR,IAAI;IAyBP,MAAM,CAAC,eAAe,CACpB,EAAE,EAAE,YAAY,EAChB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,UAAU,EAAE,EACtB,aAAa,EAAE,OAAO,EACtB,GAAG,EAAE,IAAI,GACR,IAAI;IA8NP,MAAM,CAAC,MAAM,CACX,EAAE,EAAE,YAAY,EAChB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EAAE,EACb,QAAQ,EAAE,MAAM,EAAE,GAAG,SAAS,EAC9B,GAAG,EAAE,IAAI,GACR,MAAM,EAAE;IA2BX,MAAM,CAAC,OAAO,CAAC,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI;IAUnE,MAAM,CAAC,KAAK,CACV,EAAE,EAAE,YAAY,EAChB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,IAAI,GACR,GAAG,CAAC,MAAM,CAAC;CAWf"}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { policies } from 'pg-boss';
|
|
3
|
+
import { transaction } from '@zukhruf/sqlite-transaction';
|
|
4
|
+
import { CompletionData } from "./completion-data.js";
|
|
5
|
+
import { DatabaseError } from "./database-error.js";
|
|
6
|
+
import { Database } from "./database.js";
|
|
7
|
+
import { JobRows } from "./job-rows.js";
|
|
8
|
+
import { QueueRows } from "./queue-rows.js";
|
|
9
|
+
import { Row } from "./rows.js";
|
|
10
|
+
import { SqlValues } from "./sql-values.js";
|
|
11
|
+
import { Uuid } from "./uuid.js";
|
|
12
|
+
// pg-boss's attemptFence (node_modules/pg-boss/dist/plans.js:2051-2054): a
|
|
13
|
+
// settle given the attempt it was claimed at touches the job only while that
|
|
14
|
+
// attempt still holds it.
|
|
15
|
+
const ATTEMPT_FENCE = "AND state = 'active' AND retry_count = ?";
|
|
16
|
+
export class JobSettler {
|
|
17
|
+
// pg-boss's mapCommandResponse over settledCountAndIds (node_modules/pg-boss/
|
|
18
|
+
// dist/manager.js:1623-1632, plans.js:2413-2415): the ids a settle touched,
|
|
19
|
+
// each once, and their count.
|
|
20
|
+
static response(ids, settled) {
|
|
21
|
+
return {
|
|
22
|
+
jobs: ids,
|
|
23
|
+
requested: ids.length,
|
|
24
|
+
affected: settled.length,
|
|
25
|
+
settled,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
static complete(db, name, ids, attempts, data, now) {
|
|
29
|
+
const output = CompletionData.serialize(data);
|
|
30
|
+
JobSettler.#completeEach(db, name, ids.map((id, index) => ({ id, attempt: attempts[index], output })), now);
|
|
31
|
+
}
|
|
32
|
+
// completeJobsWithOutputs (node_modules/pg-boss/dist/plans.js:2134-2151):
|
|
33
|
+
// each job its own output.
|
|
34
|
+
static completeWithOutputs(db, name, outcomes, now) {
|
|
35
|
+
JobSettler.#completeEach(db, name, JobSettler.#serializeOutputs(outcomes), now);
|
|
36
|
+
}
|
|
37
|
+
static #completeEach(db, name, settles, now) {
|
|
38
|
+
const isoNow = SqlValues.asIso(now);
|
|
39
|
+
const statement = db.prepare(`UPDATE pgboss_job
|
|
40
|
+
SET state = 'completed', completed_on = ?, output = ?
|
|
41
|
+
WHERE queue_name = ? AND id = ? ${ATTEMPT_FENCE}`);
|
|
42
|
+
transaction(db, () => {
|
|
43
|
+
for (const { id, attempt, output } of settles) {
|
|
44
|
+
statement.run(isoNow, output, name, id, attempt ?? null);
|
|
45
|
+
}
|
|
46
|
+
}, { mode: 'immediate' });
|
|
47
|
+
}
|
|
48
|
+
// fail() past its argument checks, for any value: a handler's throw or
|
|
49
|
+
// shutdown's message reach it as they are (manager.js:639-655, 893).
|
|
50
|
+
static fail(db, name, ids, data, attempts, now) {
|
|
51
|
+
// Postgres reads the bound ids before the output (manager.js:1691).
|
|
52
|
+
const uuids = ids.map((jobId) => Uuid.canonical(jobId));
|
|
53
|
+
const output = CompletionData.serialize(data);
|
|
54
|
+
return JobSettler.#failEach(db, name, uuids.map((id, index) => ({ id, attempt: attempts?.[index], output })), false, now);
|
|
55
|
+
}
|
|
56
|
+
// failJobs as the supervisor runs it (node_modules/pg-boss/dist/plans.js:
|
|
57
|
+
// 2372-2386, 2403-2408): every job `where` selects, unfenced, with one
|
|
58
|
+
// output, in the select's transaction.
|
|
59
|
+
static failJobs(db, [where, ...values], output, now) {
|
|
60
|
+
transaction(db, () => {
|
|
61
|
+
const selected = db
|
|
62
|
+
.prepare(`SELECT queue_name, id FROM pgboss_job WHERE ${where} ORDER BY rowid`)
|
|
63
|
+
.all(...values);
|
|
64
|
+
for (const row of selected) {
|
|
65
|
+
JobSettler.#failOne(db, Row.readString(row, 'queue_name'), { id: Row.readString(row, 'id'), attempt: undefined, output }, false, now);
|
|
66
|
+
}
|
|
67
|
+
}, { mode: 'immediate' });
|
|
68
|
+
}
|
|
69
|
+
// failJobsByIdWithOutputs, or with forceTerminal deadLetterJobsByIdWithOutputs
|
|
70
|
+
// (plans.js:2646-2672): each job its own output.
|
|
71
|
+
static failWithOutputs(db, name, outcomes, forceTerminal, now) {
|
|
72
|
+
JobSettler.#failEach(db, name, JobSettler.#serializeOutputs(outcomes), forceTerminal, now);
|
|
73
|
+
}
|
|
74
|
+
// Every output of a group is serialized before its statement runs
|
|
75
|
+
// (manager.js:412, 422, 447, 451).
|
|
76
|
+
static #serializeOutputs(outcomes) {
|
|
77
|
+
const outputs = CompletionData.serializeAll(outcomes.map(({ output }) => output));
|
|
78
|
+
return outcomes.map(({ id, retryCount }, index) => ({
|
|
79
|
+
id,
|
|
80
|
+
attempt: retryCount,
|
|
81
|
+
output: outputs[index] ?? null,
|
|
82
|
+
}));
|
|
83
|
+
}
|
|
84
|
+
static #failEach(db, name, settles, forceTerminal, now) {
|
|
85
|
+
const settled = JobSettler.#settleEach(db, settles, (settle) => JobSettler.#failOne(db, name, settle, forceTerminal, now));
|
|
86
|
+
return [...settled];
|
|
87
|
+
}
|
|
88
|
+
// One transaction over the ids; the set holds those settleOne reports it
|
|
89
|
+
// touched, by index into ids.
|
|
90
|
+
static #settleEach(db, items, settleOne) {
|
|
91
|
+
const settled = new Set();
|
|
92
|
+
transaction(db, () => {
|
|
93
|
+
for (const item of items) {
|
|
94
|
+
if (settleOne(item)) {
|
|
95
|
+
settled.add(item.id);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}, { mode: 'immediate' });
|
|
99
|
+
return settled;
|
|
100
|
+
}
|
|
101
|
+
static #failOne(db, name, { id, attempt, output }, forceTerminal, now) {
|
|
102
|
+
const fenced = attempt !== undefined;
|
|
103
|
+
const row = db
|
|
104
|
+
.prepare(`SELECT * FROM pgboss_job
|
|
105
|
+
WHERE queue_name = ? AND id = ? AND state IN ('created', 'retry', 'active')
|
|
106
|
+
${fenced ? ATTEMPT_FENCE : ''}`)
|
|
107
|
+
.get(name, id, ...(fenced ? [attempt] : []));
|
|
108
|
+
if (!row) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
const job = JobRows.decode(row);
|
|
112
|
+
const settle = db.prepare(`UPDATE pgboss_job
|
|
113
|
+
SET state = ?,
|
|
114
|
+
start_after = ?,
|
|
115
|
+
completed_on = ?,
|
|
116
|
+
failed_on = ?,
|
|
117
|
+
output = ?,
|
|
118
|
+
heartbeat_on = NULL,
|
|
119
|
+
lease_expires_on = NULL
|
|
120
|
+
WHERE queue_name = ? AND id = ?`);
|
|
121
|
+
const isoNow = SqlValues.asIso(now);
|
|
122
|
+
// failJobsBody (node_modules/pg-boss/dist/plans.js:2430-2645): retry while
|
|
123
|
+
// attempts remain, or with forceTerminal fail at once with the retry's
|
|
124
|
+
// start_after (2431-2439, 2494-2503); a row the key's unique index refuses
|
|
125
|
+
// fails for good instead (2529, 2607), keeping its start_after. With the
|
|
126
|
+
// attempts spent, the CASEs compute that same failed row.
|
|
127
|
+
if (job.retry_count < job.retry_limit) {
|
|
128
|
+
const completedOn = forceTerminal ? isoNow : null;
|
|
129
|
+
const landed = JobSettler.#unlessRefused(() => settle.run(forceTerminal ? 'failed' : 'retry', SqlValues.asIso(JobSettler.#nextRetryStartAfter(job, now)), completedOn, completedOn, output, name, id));
|
|
130
|
+
if (landed) {
|
|
131
|
+
if (forceTerminal) {
|
|
132
|
+
JobSettler.#deadLetter(db, job, output, now);
|
|
133
|
+
}
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
try {
|
|
138
|
+
settle.run('failed', job.start_after, isoNow, isoNow, output, name, id);
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
// The failed row has no ON CONFLICT (2532-2609): only key_strict_fifo's
|
|
142
|
+
// job_i8 holds failed jobs, and its refusal rolls the call back.
|
|
143
|
+
if (Database.isUniqueViolation(error) &&
|
|
144
|
+
job.policy === policies.key_strict_fifo) {
|
|
145
|
+
throw new DatabaseError('duplicate key value violates unique constraint "job_common_i8"', '23505');
|
|
146
|
+
}
|
|
147
|
+
throw error;
|
|
148
|
+
}
|
|
149
|
+
JobSettler.#deadLetter(db, job, output, now);
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
// ON CONFLICT DO NOTHING (plans.js:2529): false when a unique index refused
|
|
153
|
+
// the write.
|
|
154
|
+
static #unlessRefused(write) {
|
|
155
|
+
try {
|
|
156
|
+
write();
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
if (Database.isUniqueViolation(error)) {
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
throw error;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// plans.js:2494-2503: retry_delay seconds, or with backoff
|
|
167
|
+
// max(retry_delay, 1)·2^e/2·(1 + random()) for e = min(16, retry_count + 1),
|
|
168
|
+
// capped by retry_delay_max when one is set.
|
|
169
|
+
static #nextRetryStartAfter(row, now) {
|
|
170
|
+
if (!row.retry_backoff) {
|
|
171
|
+
return SqlValues.addSeconds(now, row.retry_delay_seconds);
|
|
172
|
+
}
|
|
173
|
+
const half = 2 ** Math.min(16, row.retry_count + 1) / 2;
|
|
174
|
+
const backoff = Math.max(row.retry_delay_seconds, 1) * (half + half * Math.random());
|
|
175
|
+
const cap = row.retry_delay_max_seconds;
|
|
176
|
+
return SqlValues.addSeconds(now, cap === null ? backoff : Math.min(cap, backoff));
|
|
177
|
+
}
|
|
178
|
+
// plans.js:2615-2643: a job that ends failed is copied into its dead letter
|
|
179
|
+
// queue as a new job with that queue's retry settings, retention, expiry,
|
|
180
|
+
// deletion and heartbeat, the job's data, priority, key and group, and its
|
|
181
|
+
// lineage.
|
|
182
|
+
static #deadLetter(db, job, output, now) {
|
|
183
|
+
if (job.dead_letter === null) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
const found = db
|
|
187
|
+
.prepare('SELECT * FROM pgboss_queue WHERE name = ?')
|
|
188
|
+
.get(job.dead_letter);
|
|
189
|
+
if (found === undefined) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const queue = QueueRows.decode(found);
|
|
193
|
+
db.prepare(`INSERT INTO pgboss_job (
|
|
194
|
+
id, queue_name, data, policy, priority, retry_limit, retry_backoff,
|
|
195
|
+
retry_delay_seconds, start_after, created_on, keep_until,
|
|
196
|
+
retention_seconds, deletion_seconds, expire_seconds, singleton_key,
|
|
197
|
+
group_id, group_tier, heartbeat_seconds, source_name, source_id,
|
|
198
|
+
source_created_on, source_retry_count, source_output, source_root_id
|
|
199
|
+
) VALUES (?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(randomUUID(), queue.name, job.data, job.priority, queue.retry_limit, queue.retry_backoff, queue.retry_delay_seconds, SqlValues.asIso(now), SqlValues.asIso(now), SqlValues.asIso(SqlValues.addSeconds(now, queue.retention_seconds)), queue.retention_seconds, queue.deletion_seconds, queue.expire_seconds, job.singleton_key, job.group_id, job.group_tier, queue.heartbeat_seconds, job.queue_name, job.id, job.created_on, job.retry_count, output, job.source_root_id ?? job.id);
|
|
200
|
+
}
|
|
201
|
+
static cancel(db, name, ids, attempts, now) {
|
|
202
|
+
const uuids = ids.map((jobId) => Uuid.canonical(jobId));
|
|
203
|
+
const isoNow = SqlValues.asIso(now);
|
|
204
|
+
const statement = db.prepare(`UPDATE pgboss_job
|
|
205
|
+
SET state = 'cancelled', completed_on = ?, cancelled_on = ?
|
|
206
|
+
WHERE queue_name = ?
|
|
207
|
+
AND id = ?
|
|
208
|
+
AND state IN ('created', 'retry', 'active')
|
|
209
|
+
${attempts ? ATTEMPT_FENCE : ''}`);
|
|
210
|
+
const targets = uuids.map((id, index) => ({
|
|
211
|
+
id,
|
|
212
|
+
fence: attempts ? [attempts[index] ?? null] : [],
|
|
213
|
+
}));
|
|
214
|
+
const settled = JobSettler.#settleEach(db, targets, ({ id, fence }) => {
|
|
215
|
+
const { changes } = statement.run(isoNow, isoNow, name, id, ...fence);
|
|
216
|
+
return Number(changes) > 0;
|
|
217
|
+
});
|
|
218
|
+
return [...settled];
|
|
219
|
+
}
|
|
220
|
+
// restoreJobs (node_modules/pg-boss/dist/plans.js:2201-2209): back to
|
|
221
|
+
// created whatever the state, unfenced, and with started_on cleared so the
|
|
222
|
+
// next claim spends no attempt.
|
|
223
|
+
static restore(db, name, ids) {
|
|
224
|
+
db.prepare(`UPDATE pgboss_job
|
|
225
|
+
SET state = 'created', started_on = NULL, heartbeat_on = NULL
|
|
226
|
+
WHERE queue_name = ? AND id IN (${ids.map(() => '?').join(', ')})`).run(name, ...ids);
|
|
227
|
+
}
|
|
228
|
+
// pg-boss's touch() with the attempts the heartbeat holds (manager.js:
|
|
229
|
+
// 1994-2002, plans.js:2387-2400): the ids whose heartbeat it refreshed.
|
|
230
|
+
static touch(db, name, held, now) {
|
|
231
|
+
const isoNow = SqlValues.asIso(now);
|
|
232
|
+
const statement = db.prepare(`UPDATE pgboss_job SET heartbeat_on = ?
|
|
233
|
+
WHERE queue_name = ? AND id = ? ${ATTEMPT_FENCE}`);
|
|
234
|
+
return JobSettler.#settleEach(db, held, ({ id, retry_count }) => {
|
|
235
|
+
const { changes } = statement.run(isoNow, name, id, retry_count);
|
|
236
|
+
return Number(changes) > 0;
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
//# sourceMappingURL=job-settler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"job-settler.js","sourceRoot":"","sources":["../src/job-settler.ts"],"names":[],"mappings":"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"}
|
package/dist/jsonb.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsonb.d.ts","sourceRoot":"","sources":["../src/jsonb.ts"],"names":[],"mappings":"AASA,qBAAa,KAAK;;IAChB,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO;IA6B5D,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM;IAsBxC,MAAM,CAAC,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;CA2CzC"}
|
package/dist/jsonb.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { DatabaseError } from "./database-error.js";
|
|
2
|
+
// Postgres jsonb containment (`@>`), which pg-boss's findJobs uses for its
|
|
3
|
+
// `data` filter (node_modules/pg-boss/dist/plans.js:3702). Rules from
|
|
4
|
+
// https://www.postgresql.org/docs/current/datatype-json.html#JSON-CONTAINMENT:
|
|
5
|
+
// an object contains each key of the needle recursively, an array contains
|
|
6
|
+
// each needle element somewhere (order and duplicates ignored), and scalars
|
|
7
|
+
// must be equal. Postgres's one top-level exception, an array containing a
|
|
8
|
+
// bare scalar, cannot arise: findJobs's `data` is always an object.
|
|
9
|
+
export class Jsonb {
|
|
10
|
+
static contains(haystack, needle) {
|
|
11
|
+
if (Array.isArray(needle)) {
|
|
12
|
+
return (Array.isArray(haystack) &&
|
|
13
|
+
needle.every((element) => haystack.some((candidate) => Jsonb.contains(candidate, element))));
|
|
14
|
+
}
|
|
15
|
+
if (Jsonb.#isObject(needle)) {
|
|
16
|
+
if (!Jsonb.#isObject(haystack)) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
const fields = new Map(Object.entries(haystack));
|
|
20
|
+
return Object.entries(needle).every(([key, value]) => fields.has(key) && Jsonb.contains(fields.get(key), value));
|
|
21
|
+
}
|
|
22
|
+
return haystack === needle;
|
|
23
|
+
}
|
|
24
|
+
// The JSON text a jsonb column stores for a value bound as a query
|
|
25
|
+
// parameter. pg-boss's drivers pass a string through as JSON text and send
|
|
26
|
+
// anything else as JSON (node_modules/pg/lib/utils.js:79, 92); PGlite's
|
|
27
|
+
// json serializer writes a bigint as its string (@electric-sql/pglite
|
|
28
|
+
// 0.5.8 src/types.ts:106-114). The text travels as UTF-8, a raw lone
|
|
29
|
+
// surrogate as U+FFFD, as node:sqlite binds it too. Postgres's jsonb input
|
|
30
|
+
// then rejects text that is not JSON and the first escape it cannot store.
|
|
31
|
+
static parameter(value) {
|
|
32
|
+
const serialized = typeof value === 'string'
|
|
33
|
+
? value
|
|
34
|
+
: JSON.stringify(value, (_, item) => typeof item === 'bigint' ? item.toString() : item);
|
|
35
|
+
if (serialized === undefined) {
|
|
36
|
+
throw new DatabaseError('invalid input syntax for type json', '22P02');
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
JSON.parse(serialized);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
throw new DatabaseError('invalid input syntax for type json', '22P02');
|
|
43
|
+
}
|
|
44
|
+
Jsonb.assertEscapes(serialized);
|
|
45
|
+
return serialized;
|
|
46
|
+
}
|
|
47
|
+
// Postgres's JSON lexer reads the \u escapes in text order and refuses the
|
|
48
|
+
// first one a stored value cannot hold: \u0000 (22P05), or a surrogate
|
|
49
|
+
// escape that is not a high one immediately followed by a low one (22P02).
|
|
50
|
+
static assertEscapes(text) {
|
|
51
|
+
const refused = Jsonb.#refusedEscape(text);
|
|
52
|
+
if (refused !== undefined) {
|
|
53
|
+
throw refused;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
static #refusedEscape(text) {
|
|
57
|
+
const invalid = new DatabaseError('invalid input syntax for type json', '22P02');
|
|
58
|
+
let pairEndsAt;
|
|
59
|
+
for (const escape of text.matchAll(/\\(?:u([0-9a-fA-F]{4})|[^u])/g)) {
|
|
60
|
+
const code = escape[1] === undefined ? undefined : Number.parseInt(escape[1], 16);
|
|
61
|
+
const low = code !== undefined && code >= 0xdc00 && code <= 0xdfff;
|
|
62
|
+
if (pairEndsAt !== undefined) {
|
|
63
|
+
if (!low || escape.index !== pairEndsAt) {
|
|
64
|
+
return invalid;
|
|
65
|
+
}
|
|
66
|
+
pairEndsAt = undefined;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (code === 0) {
|
|
70
|
+
return new DatabaseError('unsupported Unicode escape sequence', '22P05');
|
|
71
|
+
}
|
|
72
|
+
if (low) {
|
|
73
|
+
return invalid;
|
|
74
|
+
}
|
|
75
|
+
if (code !== undefined && code >= 0xd800 && code <= 0xdbff) {
|
|
76
|
+
pairEndsAt = escape.index + escape[0].length;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return pairEndsAt === undefined ? undefined : invalid;
|
|
80
|
+
}
|
|
81
|
+
static #isObject(value) {
|
|
82
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=jsonb.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsonb.js","sourceRoot":"","sources":["../src/jsonb.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { GroupConcurrencyConfig } from 'pg-boss';
|
|
2
|
+
import type { JobRow } from './job-rows.ts';
|
|
3
|
+
export declare class LocalGroups {
|
|
4
|
+
#private;
|
|
5
|
+
configure(name: string, localGroupConcurrency: number | GroupConcurrencyConfig): void;
|
|
6
|
+
atCapacity(name: string): string[];
|
|
7
|
+
start(name: string, jobs: JobRow[]): {
|
|
8
|
+
allowed: JobRow[];
|
|
9
|
+
excess: JobRow[];
|
|
10
|
+
grouped: JobRow[];
|
|
11
|
+
};
|
|
12
|
+
end(name: string, grouped: JobRow[]): void;
|
|
13
|
+
forget(name: string): void;
|
|
14
|
+
clear(): void;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=local-groups.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-groups.d.ts","sourceRoot":"","sources":["../src/local-groups.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAEtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAK5C,qBAAa,WAAW;;IAMtB,SAAS,CACP,IAAI,EAAE,MAAM,EACZ,qBAAqB,EAAE,MAAM,GAAG,sBAAsB,GACrD,IAAI;IAgBP,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE;IAclC,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE;;;;;IAsBlC,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI;IAS1C,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAO1B,KAAK,IAAI,IAAI;CA6Cd"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// pg-boss's localGroupConcurrency (node_modules/pg-boss/dist/manager.js:
|
|
2
|
+
// 226-282, 454-501): this process's running jobs per group of each queue,
|
|
3
|
+
// counted in memory and never shared with another process.
|
|
4
|
+
export class LocalGroups {
|
|
5
|
+
#configs = new Map();
|
|
6
|
+
#active = new Map();
|
|
7
|
+
#maxLimits = new Map();
|
|
8
|
+
// manager.js:454-462
|
|
9
|
+
configure(name, localGroupConcurrency) {
|
|
10
|
+
const config = typeof localGroupConcurrency === 'number'
|
|
11
|
+
? { default: localGroupConcurrency }
|
|
12
|
+
: localGroupConcurrency;
|
|
13
|
+
this.#configs.set(name, config);
|
|
14
|
+
this.#maxLimits.set(name, config.tiers
|
|
15
|
+
? Math.max(config.default, ...Object.values(config.tiers))
|
|
16
|
+
: config.default);
|
|
17
|
+
}
|
|
18
|
+
// The groups with no room left for any tier, which a fetch skips
|
|
19
|
+
// (manager.js:235-256).
|
|
20
|
+
atCapacity(name) {
|
|
21
|
+
const config = this.#configs.get(name);
|
|
22
|
+
const counts = this.#active.get(name);
|
|
23
|
+
if (!config || !counts) {
|
|
24
|
+
return [];
|
|
25
|
+
}
|
|
26
|
+
const maxLimit = this.#maxLimits.get(name) ?? config.default;
|
|
27
|
+
return Array.from(counts)
|
|
28
|
+
.filter(([, count]) => count >= maxLimit)
|
|
29
|
+
.map(([groupId]) => groupId);
|
|
30
|
+
}
|
|
31
|
+
// Counts each job that fits its group's limit, in batch order; a job
|
|
32
|
+
// without a group always fits and is not counted (manager.js:472-494).
|
|
33
|
+
start(name, jobs) {
|
|
34
|
+
const allowed = [];
|
|
35
|
+
const excess = [];
|
|
36
|
+
const grouped = [];
|
|
37
|
+
for (const job of jobs) {
|
|
38
|
+
if (!job.group_id) {
|
|
39
|
+
allowed.push(job);
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
const count = this.#active.get(name)?.get(job.group_id) || 0;
|
|
43
|
+
if (count < this.#limit(name, job.group_tier)) {
|
|
44
|
+
this.#increment(name, job.group_id);
|
|
45
|
+
allowed.push(job);
|
|
46
|
+
grouped.push(job);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
excess.push(job);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return { allowed, excess, grouped };
|
|
53
|
+
}
|
|
54
|
+
// manager.js:495-501
|
|
55
|
+
end(name, grouped) {
|
|
56
|
+
for (const job of grouped) {
|
|
57
|
+
if (job.group_id) {
|
|
58
|
+
this.#decrement(name, job.group_id);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// manager.js:463-471, once no live worker is left on the queue.
|
|
63
|
+
forget(name) {
|
|
64
|
+
this.#configs.delete(name);
|
|
65
|
+
this.#active.delete(name);
|
|
66
|
+
this.#maxLimits.delete(name);
|
|
67
|
+
}
|
|
68
|
+
// manager.js:876-879
|
|
69
|
+
clear() {
|
|
70
|
+
this.#configs.clear();
|
|
71
|
+
this.#active.clear();
|
|
72
|
+
this.#maxLimits.clear();
|
|
73
|
+
}
|
|
74
|
+
// `in`, as pg-boss looks a tier up, so an inherited property such as
|
|
75
|
+
// `constructor` is found and no count is below it (manager.js:226-234).
|
|
76
|
+
#limit(name, groupTier) {
|
|
77
|
+
const config = this.#configs.get(name);
|
|
78
|
+
if (!config) {
|
|
79
|
+
return Infinity;
|
|
80
|
+
}
|
|
81
|
+
if (groupTier && config.tiers && groupTier in config.tiers) {
|
|
82
|
+
const limit = config.tiers[groupTier];
|
|
83
|
+
// Never undefined: an own tier is an integer (Attorney's
|
|
84
|
+
// groupConcurrency check) and an inherited one is a function.
|
|
85
|
+
if (limit !== undefined) {
|
|
86
|
+
return limit;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return config.default;
|
|
90
|
+
}
|
|
91
|
+
#increment(name, groupId) {
|
|
92
|
+
let counts = this.#active.get(name);
|
|
93
|
+
if (!counts) {
|
|
94
|
+
counts = new Map();
|
|
95
|
+
this.#active.set(name, counts);
|
|
96
|
+
}
|
|
97
|
+
counts.set(groupId, (counts.get(groupId) || 0) + 1);
|
|
98
|
+
}
|
|
99
|
+
#decrement(name, groupId) {
|
|
100
|
+
const counts = this.#active.get(name);
|
|
101
|
+
if (!counts) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const count = counts.get(groupId) || 0;
|
|
105
|
+
if (count <= 1) {
|
|
106
|
+
counts.delete(groupId);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
counts.set(groupId, count - 1);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=local-groups.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-groups.js","sourceRoot":"","sources":["../src/local-groups.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"naive-timestamp.d.ts","sourceRoot":"","sources":["../src/naive-timestamp.ts"],"names":[],"mappings":"AAOA,qBAAa,cAAc;;IAIzB,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,GAAG,MAAM;IAIrC,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;CAerC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// pg-boss stores a throttle slot as `timestamp` without a time zone
|
|
2
|
+
// (node_modules/pg-boss/dist/plans.js:2279), and Postgres drivers read such a
|
|
3
|
+
// value as local wall-clock time: node-postgres builds it with
|
|
4
|
+
// `new Date(year, month, day, ...)` (node_modules/postgres-date/index.js:50),
|
|
5
|
+
// and PGlite does the same, so `singletonOn` lands shifted by the process's
|
|
6
|
+
// UTC offset. This stores the slot's UTC wall clock with no zone and reads it
|
|
7
|
+
// back the same way.
|
|
8
|
+
export class NaiveTimestamp {
|
|
9
|
+
static #shape = /^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})\.(\d{3})$/;
|
|
10
|
+
static fromUtc(instant) {
|
|
11
|
+
return instant.toISOString().replace('T', ' ').replace('Z', '');
|
|
12
|
+
}
|
|
13
|
+
static toLocal(stored) {
|
|
14
|
+
const parts = NaiveTimestamp.#shape.exec(stored);
|
|
15
|
+
if (!parts) {
|
|
16
|
+
throw new Error(`Unreadable stored timestamp: ${stored}`);
|
|
17
|
+
}
|
|
18
|
+
return new Date(Number(parts[1]), Number(parts[2]) - 1, Number(parts[3]), Number(parts[4]), Number(parts[5]), Number(parts[6]), Number(parts[7]));
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=naive-timestamp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"naive-timestamp.js","sourceRoot":"","sources":["../src/naive-timestamp.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,8EAA8E;AAC9E,+DAA+D;AAC/D,8EAA8E;AAC9E,4EAA4E;AAC5E,8EAA8E;AAC9E,qBAAqB;AACrB,MAAM,OAAO,cAAc;IACzB,MAAM,CAAU,MAAM,GACpB,4DAA4D,CAAC;IAE/D,MAAM,CAAC,OAAO,CAAC,OAAa;QAC1B,OAAO,OAAO,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAClE,CAAC;IAED,MAAM,CAAC,OAAO,CAAC,MAAc;QAC3B,MAAM,KAAK,GAAG,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACjD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CAAC,gCAAgC,MAAM,EAAE,CAAC,CAAC;QAC5D,CAAC;QACD,OAAO,IAAI,IAAI,CACb,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAChB,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EACpB,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAChB,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAChB,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAChB,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAChB,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CACjB,CAAC;IACJ,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { QueueRow } from './queue-rows.ts';
|
|
2
|
+
export declare class QueueCache {
|
|
3
|
+
#private;
|
|
4
|
+
replace(queues: QueueRow[]): void;
|
|
5
|
+
fill(queue: QueueRow): QueueRow;
|
|
6
|
+
peek(name: string): QueueRow | undefined;
|
|
7
|
+
evict(name: string): void;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=queue-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue-cache.d.ts","sourceRoot":"","sources":["../src/queue-cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAOhD,qBAAa,UAAU;;IAGrB,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI;IAKjC,IAAI,CAAC,KAAK,EAAE,QAAQ,GAAG,QAAQ;IAS/B,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAIxC,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;CAG1B"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// pg-boss's queue cache (node_modules/pg-boss/dist/manager.js:839-864):
|
|
2
|
+
// replaced whole at start and every queueCacheIntervalSeconds, filled by a
|
|
3
|
+
// lookup that misses, and evicted by createQueue, updateQueue and deleteQueue
|
|
4
|
+
// (2016, 2067, 2086). Lookups here still read the live row; what workers take
|
|
5
|
+
// from the cache are the monitor's counts as of the entry's last read.
|
|
6
|
+
export class QueueCache {
|
|
7
|
+
#queues = new Map();
|
|
8
|
+
replace(queues) {
|
|
9
|
+
this.#queues = new Map(queues.map((queue) => [queue.name, queue]));
|
|
10
|
+
}
|
|
11
|
+
// getQueueCache: an entry already cached wins over the row just read.
|
|
12
|
+
fill(queue) {
|
|
13
|
+
const cached = this.#queues.get(queue.name);
|
|
14
|
+
if (cached) {
|
|
15
|
+
return cached;
|
|
16
|
+
}
|
|
17
|
+
this.#queues.set(queue.name, queue);
|
|
18
|
+
return queue;
|
|
19
|
+
}
|
|
20
|
+
peek(name) {
|
|
21
|
+
return this.#queues.get(name);
|
|
22
|
+
}
|
|
23
|
+
evict(name) {
|
|
24
|
+
this.#queues.delete(name);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=queue-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue-cache.js","sourceRoot":"","sources":["../src/queue-cache.ts"],"names":[],"mappings":"AAEA,wEAAwE;AACxE,2EAA2E;AAC3E,8EAA8E;AAC9E,8EAA8E;AAC9E,uEAAuE;AACvE,MAAM,OAAO,UAAU;IACrB,OAAO,GAAG,IAAI,GAAG,EAAoB,CAAC;IAEtC,OAAO,CAAC,MAAkB;QACxB,IAAI,CAAC,OAAO,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IACrE,CAAC;IAED,sEAAsE;IACtE,IAAI,CAAC,KAAe;QAClB,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC5C,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACpC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,CAAC,IAAY;QACf,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,IAAY;QAChB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;CACF"}
|