@zukhruf/sqlite-queue 0.0.0-stage → 0.3.41

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.
Files changed (115) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +151 -2
  3. package/dist/activity.d.ts +10 -0
  4. package/dist/activity.d.ts.map +1 -0
  5. package/dist/activity.js +93 -0
  6. package/dist/activity.js.map +1 -0
  7. package/dist/attorney.d.ts +35 -0
  8. package/dist/attorney.d.ts.map +1 -0
  9. package/dist/attorney.js +367 -0
  10. package/dist/attorney.js.map +1 -0
  11. package/dist/claim-timer.d.ts +8 -0
  12. package/dist/claim-timer.d.ts.map +1 -0
  13. package/dist/claim-timer.js +80 -0
  14. package/dist/claim-timer.js.map +1 -0
  15. package/dist/completion-data.d.ts +6 -0
  16. package/dist/completion-data.d.ts.map +1 -0
  17. package/dist/completion-data.js +36 -0
  18. package/dist/completion-data.js.map +1 -0
  19. package/dist/database-error.d.ts +6 -0
  20. package/dist/database-error.d.ts.map +1 -0
  21. package/dist/database-error.js +12 -0
  22. package/dist/database-error.js.map +1 -0
  23. package/dist/database.d.ts +7 -0
  24. package/dist/database.d.ts.map +1 -0
  25. package/dist/database.js +28 -0
  26. package/dist/database.js.map +1 -0
  27. package/dist/in-flight.d.ts +7 -0
  28. package/dist/in-flight.d.ts.map +1 -0
  29. package/dist/in-flight.js +24 -0
  30. package/dist/in-flight.js.map +1 -0
  31. package/dist/index.d.ts +54 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +1069 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/job-fetcher.d.ts +16 -0
  36. package/dist/job-fetcher.d.ts.map +1 -0
  37. package/dist/job-fetcher.js +227 -0
  38. package/dist/job-fetcher.js.map +1 -0
  39. package/dist/job-queue.d.ts +27 -0
  40. package/dist/job-queue.d.ts.map +1 -0
  41. package/dist/job-queue.js +2 -0
  42. package/dist/job-queue.js.map +1 -0
  43. package/dist/job-rows.d.ts +49 -0
  44. package/dist/job-rows.d.ts.map +1 -0
  45. package/dist/job-rows.js +155 -0
  46. package/dist/job-rows.js.map +1 -0
  47. package/dist/job-settler.d.ts +24 -0
  48. package/dist/job-settler.d.ts.map +1 -0
  49. package/dist/job-settler.js +240 -0
  50. package/dist/job-settler.js.map +1 -0
  51. package/dist/jsonb.d.ts +7 -0
  52. package/dist/jsonb.d.ts.map +1 -0
  53. package/dist/jsonb.js +85 -0
  54. package/dist/jsonb.js.map +1 -0
  55. package/dist/local-groups.d.ts +16 -0
  56. package/dist/local-groups.d.ts.map +1 -0
  57. package/dist/local-groups.js +113 -0
  58. package/dist/local-groups.js.map +1 -0
  59. package/dist/naive-timestamp.d.ts +6 -0
  60. package/dist/naive-timestamp.d.ts.map +1 -0
  61. package/dist/naive-timestamp.js +21 -0
  62. package/dist/naive-timestamp.js.map +1 -0
  63. package/dist/queue-cache.d.ts +9 -0
  64. package/dist/queue-cache.d.ts.map +1 -0
  65. package/dist/queue-cache.js +27 -0
  66. package/dist/queue-cache.js.map +1 -0
  67. package/dist/queue-rows.d.ts +25 -0
  68. package/dist/queue-rows.d.ts.map +1 -0
  69. package/dist/queue-rows.js +44 -0
  70. package/dist/queue-rows.js.map +1 -0
  71. package/dist/recurrence.d.ts +11 -0
  72. package/dist/recurrence.d.ts.map +1 -0
  73. package/dist/recurrence.js +226 -0
  74. package/dist/recurrence.js.map +1 -0
  75. package/dist/rows.d.ts +10 -0
  76. package/dist/rows.d.ts.map +1 -0
  77. package/dist/rows.js +46 -0
  78. package/dist/rows.js.map +1 -0
  79. package/dist/schema.d.ts +3 -0
  80. package/dist/schema.d.ts.map +1 -0
  81. package/dist/schema.js +139 -0
  82. package/dist/schema.js.map +1 -0
  83. package/dist/sql-values.d.ts +9 -0
  84. package/dist/sql-values.d.ts.map +1 -0
  85. package/dist/sql-values.js +26 -0
  86. package/dist/sql-values.js.map +1 -0
  87. package/dist/start-after.d.ts +10 -0
  88. package/dist/start-after.d.ts.map +1 -0
  89. package/dist/start-after.js +125 -0
  90. package/dist/start-after.js.map +1 -0
  91. package/dist/supervisor.d.ts +16 -0
  92. package/dist/supervisor.d.ts.map +1 -0
  93. package/dist/supervisor.js +288 -0
  94. package/dist/supervisor.js.map +1 -0
  95. package/dist/throttle.d.ts +6 -0
  96. package/dist/throttle.d.ts.map +1 -0
  97. package/dist/throttle.js +35 -0
  98. package/dist/throttle.js.map +1 -0
  99. package/dist/timekeeper.d.ts +36 -0
  100. package/dist/timekeeper.d.ts.map +1 -0
  101. package/dist/timekeeper.js +305 -0
  102. package/dist/timekeeper.js.map +1 -0
  103. package/dist/timers.d.ts +9 -0
  104. package/dist/timers.d.ts.map +1 -0
  105. package/dist/timers.js +50 -0
  106. package/dist/timers.js.map +1 -0
  107. package/dist/uuid.d.ts +7 -0
  108. package/dist/uuid.d.ts.map +1 -0
  109. package/dist/uuid.js +36 -0
  110. package/dist/uuid.js.map +1 -0
  111. package/dist/worker.d.ts +35 -0
  112. package/dist/worker.d.ts.map +1 -0
  113. package/dist/worker.js +147 -0
  114. package/dist/worker.js.map +1 -0
  115. 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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"}
@@ -0,0 +1,7 @@
1
+ export declare class Jsonb {
2
+ #private;
3
+ static contains(haystack: unknown, needle: unknown): boolean;
4
+ static parameter(value: unknown): string;
5
+ static assertEscapes(text: string): void;
6
+ }
7
+ //# sourceMappingURL=jsonb.d.ts.map
@@ -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,6 @@
1
+ export declare class NaiveTimestamp {
2
+ #private;
3
+ static fromUtc(instant: Date): string;
4
+ static toLocal(stored: string): Date;
5
+ }
6
+ //# sourceMappingURL=naive-timestamp.d.ts.map
@@ -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"}