delaykit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +264 -0
- package/dist/delaykit.d.ts +77 -0
- package/dist/delaykit.d.ts.map +1 -0
- package/dist/delaykit.js +525 -0
- package/dist/delaykit.js.map +1 -0
- package/dist/duration.d.ts +7 -0
- package/dist/duration.d.ts.map +1 -0
- package/dist/duration.js +38 -0
- package/dist/duration.js.map +1 -0
- package/dist/emitter.d.ts +9 -0
- package/dist/emitter.d.ts.map +1 -0
- package/dist/emitter.js +41 -0
- package/dist/emitter.js.map +1 -0
- package/dist/executor.d.ts +41 -0
- package/dist/executor.d.ts.map +1 -0
- package/dist/executor.js +98 -0
- package/dist/executor.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/result-handler.d.ts +23 -0
- package/dist/result-handler.d.ts.map +1 -0
- package/dist/result-handler.js +155 -0
- package/dist/result-handler.js.map +1 -0
- package/dist/schedulers/polling.d.ts +46 -0
- package/dist/schedulers/polling.d.ts.map +1 -0
- package/dist/schedulers/polling.js +148 -0
- package/dist/schedulers/polling.js.map +1 -0
- package/dist/schedulers/posthook.d.ts +29 -0
- package/dist/schedulers/posthook.d.ts.map +1 -0
- package/dist/schedulers/posthook.js +49 -0
- package/dist/schedulers/posthook.js.map +1 -0
- package/dist/stores/memory.d.ts +28 -0
- package/dist/stores/memory.d.ts.map +1 -0
- package/dist/stores/memory.js +282 -0
- package/dist/stores/memory.js.map +1 -0
- package/dist/stores/postgres-migrations.d.ts +6 -0
- package/dist/stores/postgres-migrations.d.ts.map +1 -0
- package/dist/stores/postgres-migrations.js +65 -0
- package/dist/stores/postgres-migrations.js.map +1 -0
- package/dist/stores/postgres.d.ts +32 -0
- package/dist/stores/postgres.d.ts.map +1 -0
- package/dist/stores/postgres.js +382 -0
- package/dist/stores/postgres.js.map +1 -0
- package/dist/types.d.ts +192 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -0
- package/package.json +80 -0
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
import postgres from "postgres";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { DEFAULT_TIMEOUT_MS, STALLED_GRACE_MS } from "../types.js";
|
|
4
|
+
import { MIGRATIONS, SCHEMA } from "./postgres-migrations.js";
|
|
5
|
+
// https://www.postgresql.org/docs/current/errcodes-appendix.html
|
|
6
|
+
const PG_UNIQUE_VIOLATION = "23505";
|
|
7
|
+
const PG_INVALID_TEXT_REPRESENTATION = "22P02";
|
|
8
|
+
export class PostgresStore {
|
|
9
|
+
sql;
|
|
10
|
+
constructor(sql) {
|
|
11
|
+
this.sql = sql;
|
|
12
|
+
}
|
|
13
|
+
static async connect(connectionStringOrClient, options) {
|
|
14
|
+
let sql;
|
|
15
|
+
if (typeof connectionStringOrClient === "string" || connectionStringOrClient == null) {
|
|
16
|
+
const resolved = connectionStringOrClient ?? process.env.DELAYKIT_DATABASE_URL;
|
|
17
|
+
if (!resolved) {
|
|
18
|
+
throw new Error("Database connection string is required. Pass it as the first argument or set the DELAYKIT_DATABASE_URL environment variable.");
|
|
19
|
+
}
|
|
20
|
+
sql = postgres(resolved);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
sql = connectionStringOrClient;
|
|
24
|
+
}
|
|
25
|
+
const store = new PostgresStore(sql);
|
|
26
|
+
if (options?.runMigrations !== false) {
|
|
27
|
+
await store.migrate();
|
|
28
|
+
}
|
|
29
|
+
return store;
|
|
30
|
+
}
|
|
31
|
+
async migrate() {
|
|
32
|
+
const exists = await this.sql `
|
|
33
|
+
SELECT 1 FROM information_schema.tables
|
|
34
|
+
WHERE table_schema = ${SCHEMA} AND table_name = 'migrations'
|
|
35
|
+
`;
|
|
36
|
+
let currentVersion = 0;
|
|
37
|
+
if (exists.length > 0) {
|
|
38
|
+
const result = await this.sql `
|
|
39
|
+
SELECT COALESCE(MAX(version), 0) as version FROM delaykit.migrations
|
|
40
|
+
`;
|
|
41
|
+
currentVersion = result[0].version;
|
|
42
|
+
}
|
|
43
|
+
for (const migration of MIGRATIONS) {
|
|
44
|
+
if (migration.version > currentVersion) {
|
|
45
|
+
await this.sql.unsafe(migration.sql);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async createJob(job) {
|
|
50
|
+
const id = job.id || randomUUID();
|
|
51
|
+
try {
|
|
52
|
+
const rows = await this.sql `
|
|
53
|
+
INSERT INTO delaykit.jobs (
|
|
54
|
+
id, kind, handler, key, version, claimed_version, status,
|
|
55
|
+
scheduled_for, started_at, completed_at,
|
|
56
|
+
attempt, max_attempts, scheduler_ref, last_error,
|
|
57
|
+
first_at, last_at, wait_ms, max_wait_ms
|
|
58
|
+
) VALUES (
|
|
59
|
+
${id}, ${job.kind}, ${job.handler}, ${job.key},
|
|
60
|
+
${job.version}, ${job.claimedVersion}, ${job.status},
|
|
61
|
+
${job.scheduledFor}, ${job.startedAt}, ${job.completedAt},
|
|
62
|
+
${job.attempt}, ${job.maxAttempts}, ${job.schedulerRef}, ${job.lastError},
|
|
63
|
+
${job.firstAt}, ${job.lastAt}, ${job.waitMs}, ${job.maxWaitMs}
|
|
64
|
+
)
|
|
65
|
+
RETURNING *
|
|
66
|
+
`;
|
|
67
|
+
return this.rowToJob(rows[0]);
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
if (err.code === PG_UNIQUE_VIOLATION) {
|
|
71
|
+
throw new Error(`Job with active key "${job.key}" already exists (concurrent insert)`);
|
|
72
|
+
}
|
|
73
|
+
throw err;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async getJob(id) {
|
|
77
|
+
try {
|
|
78
|
+
const rows = await this.sql `
|
|
79
|
+
SELECT * FROM delaykit.jobs WHERE id = ${id}
|
|
80
|
+
`;
|
|
81
|
+
return rows.length > 0 ? this.rowToJob(rows[0]) : null;
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
// Invalid UUID format → treat as not found
|
|
85
|
+
if (err.code === PG_INVALID_TEXT_REPRESENTATION)
|
|
86
|
+
return null;
|
|
87
|
+
throw err;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
async getActiveJobByKey(handler, key) {
|
|
91
|
+
const rows = await this.sql `
|
|
92
|
+
SELECT * FROM delaykit.jobs
|
|
93
|
+
WHERE handler = ${handler} AND key = ${key} AND status IN ('pending', 'running')
|
|
94
|
+
LIMIT 1
|
|
95
|
+
`;
|
|
96
|
+
return rows.length > 0 ? this.rowToJob(rows[0]) : null;
|
|
97
|
+
}
|
|
98
|
+
async cancelJob(id) {
|
|
99
|
+
const result = await this.sql `
|
|
100
|
+
UPDATE delaykit.jobs
|
|
101
|
+
SET status = 'cancelled', completed_at = NOW()
|
|
102
|
+
WHERE id = ${id} AND status = 'pending'
|
|
103
|
+
`;
|
|
104
|
+
return result.count > 0;
|
|
105
|
+
}
|
|
106
|
+
async updateScheduledFor(id, scheduledFor) {
|
|
107
|
+
await this.sql `
|
|
108
|
+
UPDATE delaykit.jobs
|
|
109
|
+
SET scheduled_for = ${scheduledFor}
|
|
110
|
+
WHERE id = ${id}
|
|
111
|
+
`;
|
|
112
|
+
}
|
|
113
|
+
async deleteJob(id) {
|
|
114
|
+
await this.sql `DELETE FROM delaykit.jobs WHERE id = ${id}`;
|
|
115
|
+
}
|
|
116
|
+
async updatePatternEvent(key, handler, kind, now, waitMs, maxWaitMs) {
|
|
117
|
+
const rows = await this.sql `
|
|
118
|
+
UPDATE delaykit.jobs
|
|
119
|
+
SET version = version + 1,
|
|
120
|
+
last_at = ${now},
|
|
121
|
+
first_at = CASE
|
|
122
|
+
WHEN status = 'running' AND (first_at IS NULL OR first_at <= started_at)
|
|
123
|
+
THEN ${now}
|
|
124
|
+
ELSE first_at
|
|
125
|
+
END
|
|
126
|
+
WHERE key = ${key}
|
|
127
|
+
AND status IN ('pending', 'running')
|
|
128
|
+
AND kind = ${kind}
|
|
129
|
+
AND handler = ${handler}
|
|
130
|
+
AND wait_ms = ${waitMs}
|
|
131
|
+
AND (max_wait_ms IS NOT DISTINCT FROM ${maxWaitMs})
|
|
132
|
+
RETURNING *
|
|
133
|
+
`;
|
|
134
|
+
if (rows.length === 0) {
|
|
135
|
+
// Check if mismatch vs missing
|
|
136
|
+
const existing = await this.getActiveJobByKey(handler, key);
|
|
137
|
+
if (existing) {
|
|
138
|
+
if (existing.kind !== kind) {
|
|
139
|
+
throw new Error(`Cannot use ${kind} for key "${key}": an active ${existing.kind} job exists for this key.`);
|
|
140
|
+
}
|
|
141
|
+
if (existing.handler !== handler) {
|
|
142
|
+
throw new Error(`Config mismatch for key "${key}": active job uses handler "${existing.handler}" but "${handler}" was requested.`);
|
|
143
|
+
}
|
|
144
|
+
if (existing.waitMs !== waitMs || existing.maxWaitMs !== maxWaitMs) {
|
|
145
|
+
throw new Error(`Config mismatch for key "${key}": wait/maxWait does not match active window.`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
return this.rowToJob(rows[0]);
|
|
151
|
+
}
|
|
152
|
+
async markRunning(id, version) {
|
|
153
|
+
const rows = await this.sql `
|
|
154
|
+
UPDATE delaykit.jobs
|
|
155
|
+
SET status = 'running', started_at = now(), claimed_version = ${version}
|
|
156
|
+
WHERE id = ${id} AND status = 'pending' AND version = ${version}
|
|
157
|
+
RETURNING id
|
|
158
|
+
`;
|
|
159
|
+
return rows.length > 0;
|
|
160
|
+
}
|
|
161
|
+
async markCompleted(id, version) {
|
|
162
|
+
const rows = await this.sql `
|
|
163
|
+
UPDATE delaykit.jobs
|
|
164
|
+
SET status = 'completed', completed_at = now()
|
|
165
|
+
WHERE id = ${id} AND status = 'running' AND version = ${version}
|
|
166
|
+
RETURNING id
|
|
167
|
+
`;
|
|
168
|
+
return rows.length > 0;
|
|
169
|
+
}
|
|
170
|
+
async markFailed(id, version, error) {
|
|
171
|
+
const rows = await this.sql `
|
|
172
|
+
UPDATE delaykit.jobs
|
|
173
|
+
SET status = 'failed', last_error = ${error.message}, completed_at = now()
|
|
174
|
+
WHERE id = ${id} AND status = 'running' AND version = ${version}
|
|
175
|
+
RETURNING id
|
|
176
|
+
`;
|
|
177
|
+
return rows.length > 0;
|
|
178
|
+
}
|
|
179
|
+
async retryJob(id, version, nextAttempt, scheduledFor, lastError) {
|
|
180
|
+
const rows = await this.sql `
|
|
181
|
+
UPDATE delaykit.jobs
|
|
182
|
+
SET status = 'pending', attempt = ${nextAttempt}, scheduled_for = ${scheduledFor},
|
|
183
|
+
started_at = NULL, completed_at = NULL, claimed_version = NULL,
|
|
184
|
+
last_error = ${lastError}
|
|
185
|
+
WHERE id = ${id} AND status = 'running' AND version = ${version}
|
|
186
|
+
RETURNING id
|
|
187
|
+
`;
|
|
188
|
+
return rows.length > 0;
|
|
189
|
+
}
|
|
190
|
+
async rescheduleDueAt(id, version) {
|
|
191
|
+
// Only debounce reschedules (throttle always fires), but formula handles both
|
|
192
|
+
const rows = await this.sql `
|
|
193
|
+
UPDATE delaykit.jobs
|
|
194
|
+
SET version = version + 1,
|
|
195
|
+
scheduled_for = CASE
|
|
196
|
+
WHEN kind = 'throttle' THEN first_at + (wait_ms * INTERVAL '1 millisecond')
|
|
197
|
+
ELSE LEAST(
|
|
198
|
+
last_at + (wait_ms * INTERVAL '1 millisecond'),
|
|
199
|
+
CASE WHEN max_wait_ms IS NOT NULL
|
|
200
|
+
THEN first_at + (max_wait_ms * INTERVAL '1 millisecond')
|
|
201
|
+
ELSE last_at + (wait_ms * INTERVAL '1 millisecond')
|
|
202
|
+
END
|
|
203
|
+
)
|
|
204
|
+
END
|
|
205
|
+
WHERE id = ${id} AND status = 'pending' AND version = ${version}
|
|
206
|
+
RETURNING *
|
|
207
|
+
`;
|
|
208
|
+
return rows.length > 0 ? this.rowToJob(rows[0]) : null;
|
|
209
|
+
}
|
|
210
|
+
async requeueForNextWindow(id) {
|
|
211
|
+
const rows = await this.sql `
|
|
212
|
+
UPDATE delaykit.jobs
|
|
213
|
+
SET status = 'pending',
|
|
214
|
+
version = version + 1,
|
|
215
|
+
started_at = NULL,
|
|
216
|
+
completed_at = NULL,
|
|
217
|
+
claimed_version = NULL,
|
|
218
|
+
attempt = 0,
|
|
219
|
+
scheduled_for = CASE
|
|
220
|
+
WHEN kind = 'throttle' THEN first_at + (wait_ms * INTERVAL '1 millisecond')
|
|
221
|
+
ELSE LEAST(
|
|
222
|
+
last_at + (wait_ms * INTERVAL '1 millisecond'),
|
|
223
|
+
CASE WHEN max_wait_ms IS NOT NULL
|
|
224
|
+
THEN first_at + (max_wait_ms * INTERVAL '1 millisecond')
|
|
225
|
+
ELSE last_at + (wait_ms * INTERVAL '1 millisecond')
|
|
226
|
+
END
|
|
227
|
+
)
|
|
228
|
+
END
|
|
229
|
+
WHERE id = ${id} AND status = 'running'
|
|
230
|
+
RETURNING *
|
|
231
|
+
`;
|
|
232
|
+
return rows.length > 0 ? this.rowToJob(rows[0]) : null;
|
|
233
|
+
}
|
|
234
|
+
async replaceJob(id, scheduledFor, maxAttempts) {
|
|
235
|
+
const rows = await this.sql `
|
|
236
|
+
UPDATE delaykit.jobs
|
|
237
|
+
SET version = version + 1, scheduled_for = ${scheduledFor}, status = 'pending',
|
|
238
|
+
attempt = 0, max_attempts = ${maxAttempts}, scheduler_ref = NULL,
|
|
239
|
+
last_error = NULL, started_at = NULL, completed_at = NULL, claimed_version = NULL
|
|
240
|
+
WHERE id = ${id} AND status = 'pending'
|
|
241
|
+
RETURNING *
|
|
242
|
+
`;
|
|
243
|
+
return rows.length > 0 ? this.rowToJob(rows[0]) : null;
|
|
244
|
+
}
|
|
245
|
+
async updateSchedulerRef(id, version, ref) {
|
|
246
|
+
const result = await this.sql `
|
|
247
|
+
UPDATE delaykit.jobs
|
|
248
|
+
SET scheduler_ref = ${ref}
|
|
249
|
+
WHERE id = ${id} AND version = ${version}
|
|
250
|
+
`;
|
|
251
|
+
return result.count > 0;
|
|
252
|
+
}
|
|
253
|
+
async reclaimStalled(id, leaseMs) {
|
|
254
|
+
// Pattern with version advance: requeue fresh window
|
|
255
|
+
const requeued = await this.sql `
|
|
256
|
+
UPDATE delaykit.jobs
|
|
257
|
+
SET status = 'pending',
|
|
258
|
+
version = version + 1,
|
|
259
|
+
attempt = 0,
|
|
260
|
+
started_at = NULL, completed_at = NULL, claimed_version = NULL,
|
|
261
|
+
scheduled_for = CASE
|
|
262
|
+
WHEN kind = 'throttle' THEN first_at + (wait_ms * INTERVAL '1 millisecond')
|
|
263
|
+
ELSE LEAST(
|
|
264
|
+
last_at + (wait_ms * INTERVAL '1 millisecond'),
|
|
265
|
+
CASE WHEN max_wait_ms IS NOT NULL
|
|
266
|
+
THEN first_at + (max_wait_ms * INTERVAL '1 millisecond')
|
|
267
|
+
ELSE last_at + (wait_ms * INTERVAL '1 millisecond')
|
|
268
|
+
END
|
|
269
|
+
)
|
|
270
|
+
END
|
|
271
|
+
WHERE id = ${id} AND status = 'running'
|
|
272
|
+
AND started_at IS NOT NULL
|
|
273
|
+
AND started_at + (${leaseMs} * INTERVAL '1 millisecond') < now()
|
|
274
|
+
AND kind != 'once'
|
|
275
|
+
AND claimed_version IS NOT NULL
|
|
276
|
+
AND version > claimed_version
|
|
277
|
+
RETURNING *
|
|
278
|
+
`;
|
|
279
|
+
if (requeued.length > 0)
|
|
280
|
+
return this.rowToJob(requeued[0]);
|
|
281
|
+
// Normal reclaim: increment attempt, caller handles exhaustion + onFailure
|
|
282
|
+
const rows = await this.sql `
|
|
283
|
+
UPDATE delaykit.jobs
|
|
284
|
+
SET status = 'pending', attempt = attempt + 1,
|
|
285
|
+
started_at = NULL, claimed_version = NULL
|
|
286
|
+
WHERE id = ${id} AND status = 'running'
|
|
287
|
+
AND started_at IS NOT NULL
|
|
288
|
+
AND started_at + (${leaseMs} * INTERVAL '1 millisecond') < now()
|
|
289
|
+
RETURNING *
|
|
290
|
+
`;
|
|
291
|
+
return rows.length > 0 ? this.rowToJob(rows[0]) : null;
|
|
292
|
+
}
|
|
293
|
+
async reclaimStalledJobs(handlerTimeouts) {
|
|
294
|
+
const rows = await this.sql `
|
|
295
|
+
SELECT * FROM delaykit.jobs
|
|
296
|
+
WHERE status = 'running' AND started_at IS NOT NULL
|
|
297
|
+
`;
|
|
298
|
+
const reclaimed = [];
|
|
299
|
+
const now = Date.now();
|
|
300
|
+
for (const row of rows) {
|
|
301
|
+
const job = this.rowToJob(row);
|
|
302
|
+
const timeout = handlerTimeouts.get(job.handler) ?? DEFAULT_TIMEOUT_MS;
|
|
303
|
+
if (now - job.startedAt.getTime() > timeout + STALLED_GRACE_MS) {
|
|
304
|
+
if (job.kind !== "once" && job.claimedVersion != null && job.version > job.claimedVersion) {
|
|
305
|
+
// Pattern with version advance: requeue fresh window
|
|
306
|
+
const requeued = await this.sql `
|
|
307
|
+
UPDATE delaykit.jobs
|
|
308
|
+
SET status = 'pending',
|
|
309
|
+
version = version + 1,
|
|
310
|
+
started_at = NULL, completed_at = NULL, claimed_version = NULL,
|
|
311
|
+
attempt = 0,
|
|
312
|
+
scheduled_for = CASE
|
|
313
|
+
WHEN kind = 'throttle' THEN first_at + (wait_ms * INTERVAL '1 millisecond')
|
|
314
|
+
ELSE LEAST(
|
|
315
|
+
last_at + (wait_ms * INTERVAL '1 millisecond'),
|
|
316
|
+
CASE WHEN max_wait_ms IS NOT NULL
|
|
317
|
+
THEN first_at + (max_wait_ms * INTERVAL '1 millisecond')
|
|
318
|
+
ELSE last_at + (wait_ms * INTERVAL '1 millisecond')
|
|
319
|
+
END
|
|
320
|
+
)
|
|
321
|
+
END
|
|
322
|
+
WHERE id = ${job.id} AND status = 'running'
|
|
323
|
+
RETURNING *
|
|
324
|
+
`;
|
|
325
|
+
if (requeued.length > 0)
|
|
326
|
+
reclaimed.push(this.rowToJob(requeued[0]));
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
// Reclaim: increment attempt. Caller handles exhaustion + onFailure.
|
|
330
|
+
await this.sql `
|
|
331
|
+
UPDATE delaykit.jobs
|
|
332
|
+
SET status = 'pending', attempt = attempt + 1,
|
|
333
|
+
started_at = NULL, claimed_version = NULL
|
|
334
|
+
WHERE id = ${job.id} AND status = 'running'
|
|
335
|
+
`;
|
|
336
|
+
job.status = "pending";
|
|
337
|
+
job.attempt += 1;
|
|
338
|
+
job.startedAt = null;
|
|
339
|
+
job.claimedVersion = null;
|
|
340
|
+
reclaimed.push(job);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return reclaimed;
|
|
345
|
+
}
|
|
346
|
+
async getDueJobs(limit) {
|
|
347
|
+
const rows = await this.sql `
|
|
348
|
+
SELECT * FROM delaykit.jobs
|
|
349
|
+
WHERE status = 'pending' AND scheduled_for <= now()
|
|
350
|
+
ORDER BY scheduled_for ASC
|
|
351
|
+
LIMIT ${limit}
|
|
352
|
+
`;
|
|
353
|
+
return rows.map((r) => this.rowToJob(r));
|
|
354
|
+
}
|
|
355
|
+
async close() {
|
|
356
|
+
await this.sql.end();
|
|
357
|
+
}
|
|
358
|
+
rowToJob(row) {
|
|
359
|
+
return {
|
|
360
|
+
id: row.id,
|
|
361
|
+
kind: row.kind,
|
|
362
|
+
handler: row.handler,
|
|
363
|
+
key: row.key,
|
|
364
|
+
version: row.version,
|
|
365
|
+
claimedVersion: row.claimed_version ?? null,
|
|
366
|
+
status: row.status,
|
|
367
|
+
scheduledFor: new Date(row.scheduled_for),
|
|
368
|
+
startedAt: row.started_at ? new Date(row.started_at) : null,
|
|
369
|
+
completedAt: row.completed_at ? new Date(row.completed_at) : null,
|
|
370
|
+
attempt: row.attempt,
|
|
371
|
+
maxAttempts: row.max_attempts,
|
|
372
|
+
schedulerRef: row.scheduler_ref,
|
|
373
|
+
lastError: row.last_error,
|
|
374
|
+
createdAt: new Date(row.created_at),
|
|
375
|
+
firstAt: row.first_at ? new Date(row.first_at) : null,
|
|
376
|
+
lastAt: row.last_at ? new Date(row.last_at) : null,
|
|
377
|
+
waitMs: row.wait_ms,
|
|
378
|
+
maxWaitMs: row.max_wait_ms,
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
//# sourceMappingURL=postgres.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres.js","sourceRoot":"","sources":["../../src/stores/postgres.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Job status state machine:
|
|
3
|
+
*
|
|
4
|
+
* once: pending → running → completed | failed
|
|
5
|
+
* pattern: pending → running → completed | failed | pending (requeue)
|
|
6
|
+
* any: pending → cancelled
|
|
7
|
+
*/
|
|
8
|
+
export type JobStatus = "pending" | "running" | "completed" | "failed" | "cancelled";
|
|
9
|
+
export declare const ACTIVE_STATUSES: ReadonlySet<JobStatus>;
|
|
10
|
+
export declare const DEFAULT_TIMEOUT_MS = 30000;
|
|
11
|
+
export declare const STALLED_GRACE_MS = 5000;
|
|
12
|
+
export interface Job {
|
|
13
|
+
id: string;
|
|
14
|
+
kind: "once" | "debounce" | "throttle";
|
|
15
|
+
handler: string;
|
|
16
|
+
key: string;
|
|
17
|
+
version: number;
|
|
18
|
+
claimedVersion: number | null;
|
|
19
|
+
status: JobStatus;
|
|
20
|
+
scheduledFor: Date;
|
|
21
|
+
startedAt: Date | null;
|
|
22
|
+
completedAt: Date | null;
|
|
23
|
+
attempt: number;
|
|
24
|
+
maxAttempts: number;
|
|
25
|
+
schedulerRef: string | null;
|
|
26
|
+
lastError: string | null;
|
|
27
|
+
createdAt: Date;
|
|
28
|
+
firstAt: Date | null;
|
|
29
|
+
lastAt: Date | null;
|
|
30
|
+
waitMs: number | null;
|
|
31
|
+
maxWaitMs: number | null;
|
|
32
|
+
}
|
|
33
|
+
export interface ScheduleOptions {
|
|
34
|
+
key: string;
|
|
35
|
+
delay?: string;
|
|
36
|
+
at?: Date;
|
|
37
|
+
onDuplicate?: "skip" | "replace";
|
|
38
|
+
}
|
|
39
|
+
export interface DebounceOptions {
|
|
40
|
+
key: string;
|
|
41
|
+
wait: string;
|
|
42
|
+
maxWait?: string;
|
|
43
|
+
}
|
|
44
|
+
export interface ThrottleOptions {
|
|
45
|
+
key: string;
|
|
46
|
+
wait: string;
|
|
47
|
+
}
|
|
48
|
+
export interface HandlerContext {
|
|
49
|
+
key: string;
|
|
50
|
+
job: Job;
|
|
51
|
+
signal: AbortSignal;
|
|
52
|
+
}
|
|
53
|
+
export type HandlerFn = (ctx: HandlerContext) => Promise<void>;
|
|
54
|
+
export interface RetryConfig {
|
|
55
|
+
attempts: number;
|
|
56
|
+
backoff: "exponential" | "linear" | "fixed";
|
|
57
|
+
initialDelay: string;
|
|
58
|
+
maxDelay?: string;
|
|
59
|
+
jitter?: boolean;
|
|
60
|
+
}
|
|
61
|
+
export interface HandlerConfig {
|
|
62
|
+
handler: HandlerFn;
|
|
63
|
+
timeout?: string;
|
|
64
|
+
retry?: RetryConfig;
|
|
65
|
+
onFailure?: (ctx: {
|
|
66
|
+
key: string;
|
|
67
|
+
error: Error;
|
|
68
|
+
attempts: number;
|
|
69
|
+
}) => Promise<void>;
|
|
70
|
+
}
|
|
71
|
+
export interface Store {
|
|
72
|
+
createJob(job: Omit<Job, "createdAt">): Promise<Job>;
|
|
73
|
+
getJob(id: string): Promise<Job | null>;
|
|
74
|
+
getActiveJobByKey(handler: string, key: string): Promise<Job | null>;
|
|
75
|
+
deleteJob(id: string): Promise<void>;
|
|
76
|
+
cancelJob(id: string): Promise<boolean>;
|
|
77
|
+
updateScheduledFor(id: string, scheduledFor: Date): Promise<void>;
|
|
78
|
+
updatePatternEvent(key: string, handler: string, kind: "debounce" | "throttle", now: Date, waitMs: number, maxWaitMs: number | null): Promise<Job | null>;
|
|
79
|
+
markRunning(id: string, version: number): Promise<boolean>;
|
|
80
|
+
markCompleted(id: string, version: number): Promise<boolean>;
|
|
81
|
+
markFailed(id: string, version: number, error: Error): Promise<boolean>;
|
|
82
|
+
retryJob(id: string, version: number, nextAttempt: number, scheduledFor: Date, lastError: string): Promise<boolean>;
|
|
83
|
+
rescheduleDueAt(id: string, version: number): Promise<Job | null>;
|
|
84
|
+
requeueForNextWindow(id: string): Promise<Job | null>;
|
|
85
|
+
replaceJob(id: string, scheduledFor: Date, maxAttempts: number): Promise<Job | null>;
|
|
86
|
+
updateSchedulerRef(id: string, version: number, ref: string): Promise<boolean>;
|
|
87
|
+
getDueJobs(limit: number): Promise<Job[]>;
|
|
88
|
+
reclaimStalled(id: string, leaseMs: number): Promise<Job | null>;
|
|
89
|
+
reclaimStalledJobs(handlerTimeouts: Map<string, number>): Promise<Job[]>;
|
|
90
|
+
close(): Promise<void>;
|
|
91
|
+
}
|
|
92
|
+
export interface SchedulerRetryConfig {
|
|
93
|
+
attempts: number;
|
|
94
|
+
backoff: "exponential" | "linear" | "fixed";
|
|
95
|
+
initialDelayMs: number;
|
|
96
|
+
maxDelayMs: number;
|
|
97
|
+
jitter: boolean;
|
|
98
|
+
}
|
|
99
|
+
export interface ScheduleRequest {
|
|
100
|
+
id: string;
|
|
101
|
+
version: number;
|
|
102
|
+
at: Date;
|
|
103
|
+
handler: string;
|
|
104
|
+
key?: string;
|
|
105
|
+
retry?: SchedulerRetryConfig;
|
|
106
|
+
}
|
|
107
|
+
export interface SchedulerContext {
|
|
108
|
+
store: Store;
|
|
109
|
+
handlers: Map<string, {
|
|
110
|
+
fn: (ctx: HandlerContext) => Promise<void>;
|
|
111
|
+
timeoutMs: number;
|
|
112
|
+
}>;
|
|
113
|
+
emit: EmitFn;
|
|
114
|
+
}
|
|
115
|
+
export interface Scheduler {
|
|
116
|
+
/** Maximum total attempts this scheduler supports. Omit for unlimited. */
|
|
117
|
+
maxAttempts?: number;
|
|
118
|
+
/** Called by DelayKit before start() with shared dependencies. */
|
|
119
|
+
init?(ctx: SchedulerContext): void;
|
|
120
|
+
schedule(req: ScheduleRequest): Promise<string | null>;
|
|
121
|
+
cancel(schedulerRef: string): Promise<void>;
|
|
122
|
+
start(): Promise<void>;
|
|
123
|
+
stop(): Promise<void>;
|
|
124
|
+
/** Signing key for webhook verification. Set by PosthookScheduler. */
|
|
125
|
+
signingKey?: string;
|
|
126
|
+
/** Verify a webhook delivery. Implemented by PosthookScheduler. */
|
|
127
|
+
verifyDelivery?<T = Record<string, unknown>>(body: string, headers: Headers | Record<string, string | string[] | undefined>): {
|
|
128
|
+
hookId: string;
|
|
129
|
+
data: T;
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
export interface JobScheduledEvent {
|
|
133
|
+
type: "job:scheduled";
|
|
134
|
+
job: Job;
|
|
135
|
+
timestamp: Date;
|
|
136
|
+
}
|
|
137
|
+
export interface JobStartedEvent {
|
|
138
|
+
type: "job:started";
|
|
139
|
+
job: Job;
|
|
140
|
+
timestamp: Date;
|
|
141
|
+
attempt: number;
|
|
142
|
+
}
|
|
143
|
+
export interface JobCompletedEvent {
|
|
144
|
+
type: "job:completed";
|
|
145
|
+
job: Job;
|
|
146
|
+
timestamp: Date;
|
|
147
|
+
durationMs: number;
|
|
148
|
+
}
|
|
149
|
+
export interface JobFailedEvent {
|
|
150
|
+
type: "job:failed";
|
|
151
|
+
job: Job;
|
|
152
|
+
timestamp: Date;
|
|
153
|
+
error: Error;
|
|
154
|
+
attempts: number;
|
|
155
|
+
durationMs: number;
|
|
156
|
+
}
|
|
157
|
+
export interface JobRetryingEvent {
|
|
158
|
+
type: "job:retrying";
|
|
159
|
+
job: Job;
|
|
160
|
+
timestamp: Date;
|
|
161
|
+
error: Error;
|
|
162
|
+
attempt: number;
|
|
163
|
+
nextAttempt: number;
|
|
164
|
+
scheduledFor: Date;
|
|
165
|
+
}
|
|
166
|
+
export interface JobCancelledEvent {
|
|
167
|
+
type: "job:cancelled";
|
|
168
|
+
job: Job;
|
|
169
|
+
timestamp: Date;
|
|
170
|
+
}
|
|
171
|
+
export interface JobStalledEvent {
|
|
172
|
+
type: "job:stalled";
|
|
173
|
+
job: Job;
|
|
174
|
+
timestamp: Date;
|
|
175
|
+
stalledMs: number;
|
|
176
|
+
reclaimed: boolean;
|
|
177
|
+
}
|
|
178
|
+
export interface JobEventMap {
|
|
179
|
+
"job:scheduled": JobScheduledEvent;
|
|
180
|
+
"job:started": JobStartedEvent;
|
|
181
|
+
"job:completed": JobCompletedEvent;
|
|
182
|
+
"job:failed": JobFailedEvent;
|
|
183
|
+
"job:retrying": JobRetryingEvent;
|
|
184
|
+
"job:cancelled": JobCancelledEvent;
|
|
185
|
+
"job:stalled": JobStalledEvent;
|
|
186
|
+
}
|
|
187
|
+
export type JobEventType = keyof JobEventMap;
|
|
188
|
+
export type JobEvent = JobEventMap[JobEventType];
|
|
189
|
+
export type JobEventListener<E extends JobEventType> = (event: JobEventMap[E]) => void | Promise<void>;
|
|
190
|
+
/** Typed emit function. Synchronous; listener errors are caught internally. */
|
|
191
|
+
export type EmitFn = <E extends JobEventType>(event: JobEventMap[E]) => void;
|
|
192
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AASA,MAAM,CAAC,MAAM,eAAe,GAA2B,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;AAEvF,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AACzC,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,CAAC"}
|