@absurd-sqlite/sdk 0.2.1-alpha.2 → 0.3.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/absurd.d.ts +305 -0
- package/dist/absurd.d.ts.map +1 -0
- package/dist/absurd.js +711 -0
- package/dist/absurd.js.map +1 -0
- package/dist/cjs/absurd.js +751 -0
- package/dist/cjs/index.js +22 -13
- package/dist/{sqlite.js → cjs/sqlite-connection.js} +78 -22
- package/dist/index.d.ts +100 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -12
- package/dist/index.js.map +1 -1
- package/dist/sqlite-connection.d.ts +46 -0
- package/dist/sqlite-connection.d.ts.map +1 -0
- package/dist/{cjs/sqlite.js → sqlite-connection.js} +75 -25
- package/dist/sqlite-connection.js.map +1 -0
- package/dist/sqlite-types.d.ts +1 -1
- package/dist/sqlite-types.d.ts.map +1 -1
- package/package.json +5 -4
- package/src/absurd.ts +1030 -0
- package/src/index.ts +163 -30
- package/src/sqlite-connection.ts +298 -0
- package/src/sqlite-types.ts +1 -1
- package/test/basic.test.ts +6 -6
- package/test/events.test.ts +6 -6
- package/test/index.test.ts +7 -5
- package/test/retry.test.ts +5 -5
- package/test/setup.ts +38 -44
- package/test/sqlite.test.ts +50 -19
- package/test/step.test.ts +6 -5
- package/dist/absurd-types.d.ts +0 -109
- package/dist/absurd-types.d.ts.map +0 -1
- package/dist/absurd-types.js +0 -2
- package/dist/absurd-types.js.map +0 -1
- package/dist/cjs/absurd-types.js +0 -2
- package/dist/sqlite.d.ts +0 -14
- package/dist/sqlite.d.ts.map +0 -1
- package/dist/sqlite.js.map +0 -1
- package/src/absurd-types.ts +0 -149
- package/src/sqlite.ts +0 -211
package/test/setup.ts
CHANGED
|
@@ -5,13 +5,14 @@ import { tmpdir } from "node:os";
|
|
|
5
5
|
import { join } from "node:path";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
7
|
import {
|
|
8
|
-
Absurd
|
|
8
|
+
Absurd,
|
|
9
|
+
Temporal,
|
|
9
10
|
type AbsurdHooks,
|
|
10
11
|
type JsonValue,
|
|
11
|
-
|
|
12
|
+
type SQLiteDatabase,
|
|
13
|
+
} from "../src/index";
|
|
12
14
|
|
|
13
|
-
import {
|
|
14
|
-
import type { Absurd, SQLiteDatabase } from "../src/index";
|
|
15
|
+
import { SQLiteConnection } from "../src/sqlite-connection";
|
|
15
16
|
|
|
16
17
|
// Database row types matching the SQLite schema
|
|
17
18
|
export interface TaskRow {
|
|
@@ -22,8 +23,8 @@ export interface TaskRow {
|
|
|
22
23
|
retry_strategy: JsonValue | null;
|
|
23
24
|
max_attempts: number | null;
|
|
24
25
|
cancellation: JsonValue | null;
|
|
25
|
-
enqueue_at:
|
|
26
|
-
first_started_at:
|
|
26
|
+
enqueue_at: Temporal.Instant;
|
|
27
|
+
first_started_at: Temporal.Instant | null;
|
|
27
28
|
state:
|
|
28
29
|
| "pending"
|
|
29
30
|
| "running"
|
|
@@ -34,7 +35,7 @@ export interface TaskRow {
|
|
|
34
35
|
attempts: number;
|
|
35
36
|
last_attempt_run: string | null;
|
|
36
37
|
completed_payload: JsonValue | null;
|
|
37
|
-
cancelled_at:
|
|
38
|
+
cancelled_at: Temporal.Instant | null;
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
export interface RunRow {
|
|
@@ -49,21 +50,21 @@ export interface RunRow {
|
|
|
49
50
|
| "failed"
|
|
50
51
|
| "cancelled";
|
|
51
52
|
claimed_by: string | null;
|
|
52
|
-
claim_expires_at:
|
|
53
|
-
available_at:
|
|
53
|
+
claim_expires_at: Temporal.Instant | null;
|
|
54
|
+
available_at: Temporal.Instant;
|
|
54
55
|
wake_event: string | null;
|
|
55
56
|
event_payload: JsonValue | null;
|
|
56
|
-
started_at:
|
|
57
|
-
completed_at:
|
|
58
|
-
failed_at:
|
|
57
|
+
started_at: Temporal.Instant | null;
|
|
58
|
+
completed_at: Temporal.Instant | null;
|
|
59
|
+
failed_at: Temporal.Instant | null;
|
|
59
60
|
result: JsonValue | null;
|
|
60
61
|
failure_reason: JsonValue | null;
|
|
61
|
-
created_at:
|
|
62
|
+
created_at: Temporal.Instant;
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
interface SqliteFixture {
|
|
65
66
|
db: sqlite.Database;
|
|
66
|
-
conn:
|
|
67
|
+
conn: SQLiteConnection;
|
|
67
68
|
dbPath: string;
|
|
68
69
|
cleanup: () => void;
|
|
69
70
|
}
|
|
@@ -80,7 +81,7 @@ afterAll(() => {
|
|
|
80
81
|
|
|
81
82
|
export interface TestContext {
|
|
82
83
|
absurd: Absurd;
|
|
83
|
-
pool:
|
|
84
|
+
pool: SQLiteConnection;
|
|
84
85
|
queueName: string;
|
|
85
86
|
dbPath: string;
|
|
86
87
|
cleanupTasks(): Promise<void>;
|
|
@@ -160,7 +161,7 @@ function createFixture(): SqliteFixture {
|
|
|
160
161
|
const db = new sqlite(dbPath);
|
|
161
162
|
db.loadExtension(extensionPath);
|
|
162
163
|
db.prepare("select absurd_apply_migrations()").get();
|
|
163
|
-
const conn = new
|
|
164
|
+
const conn = new SQLiteConnection(db as SQLiteDatabase);
|
|
164
165
|
|
|
165
166
|
const cleanup = () => {
|
|
166
167
|
rmSync(tempDir, { recursive: true, force: true });
|
|
@@ -175,11 +176,7 @@ export async function createTestAbsurd(
|
|
|
175
176
|
queueName: string = "default"
|
|
176
177
|
): Promise<TestContext> {
|
|
177
178
|
const fixture = createFixture();
|
|
178
|
-
const
|
|
179
|
-
db: fixture.conn,
|
|
180
|
-
queueName,
|
|
181
|
-
});
|
|
182
|
-
const absurd = absurdBase as unknown as Absurd;
|
|
179
|
+
const absurd = new Absurd(fixture.conn, { queueName });
|
|
183
180
|
|
|
184
181
|
await absurd.createQueue(queueName);
|
|
185
182
|
|
|
@@ -247,19 +244,16 @@ export async function createTestAbsurd(
|
|
|
247
244
|
extendClaim(fixture.conn, runID, extendBySeconds, queueName),
|
|
248
245
|
expectCancelledError: (promise: Promise<unknown>) =>
|
|
249
246
|
expectCancelledError(promise),
|
|
250
|
-
createClient: (options) =>
|
|
251
|
-
|
|
252
|
-
db: fixture.conn,
|
|
247
|
+
createClient: (options) =>
|
|
248
|
+
new Absurd(fixture.conn, {
|
|
253
249
|
queueName: options?.queueName ?? queueName,
|
|
254
250
|
hooks: options?.hooks,
|
|
255
|
-
})
|
|
256
|
-
return client as unknown as Absurd;
|
|
257
|
-
},
|
|
251
|
+
}),
|
|
258
252
|
};
|
|
259
253
|
}
|
|
260
254
|
|
|
261
255
|
async function setFakeNow(
|
|
262
|
-
conn:
|
|
256
|
+
conn: SQLiteConnection,
|
|
263
257
|
ts: Date | null
|
|
264
258
|
): Promise<void> {
|
|
265
259
|
if (ts === null) {
|
|
@@ -270,7 +264,7 @@ async function setFakeNow(
|
|
|
270
264
|
}
|
|
271
265
|
|
|
272
266
|
async function cleanupTasks(
|
|
273
|
-
conn:
|
|
267
|
+
conn: SQLiteConnection,
|
|
274
268
|
queue: string
|
|
275
269
|
): Promise<void> {
|
|
276
270
|
const tables = [
|
|
@@ -286,7 +280,7 @@ async function cleanupTasks(
|
|
|
286
280
|
}
|
|
287
281
|
|
|
288
282
|
async function getQueueStorageState(
|
|
289
|
-
conn:
|
|
283
|
+
conn: SQLiteConnection,
|
|
290
284
|
queue: string
|
|
291
285
|
): Promise<{ exists: boolean; tables: string[] }> {
|
|
292
286
|
const { rows } = await conn.query<{ count: number }>(
|
|
@@ -303,7 +297,7 @@ async function getQueueStorageState(
|
|
|
303
297
|
}
|
|
304
298
|
|
|
305
299
|
async function getTask(
|
|
306
|
-
conn:
|
|
300
|
+
conn: SQLiteConnection,
|
|
307
301
|
taskID: string,
|
|
308
302
|
queue: string
|
|
309
303
|
): Promise<TaskRow | null> {
|
|
@@ -330,7 +324,7 @@ async function getTask(
|
|
|
330
324
|
}
|
|
331
325
|
|
|
332
326
|
async function getRun(
|
|
333
|
-
conn:
|
|
327
|
+
conn: SQLiteConnection,
|
|
334
328
|
runID: string,
|
|
335
329
|
queue: string
|
|
336
330
|
): Promise<RunRow | null> {
|
|
@@ -358,7 +352,7 @@ async function getRun(
|
|
|
358
352
|
}
|
|
359
353
|
|
|
360
354
|
async function getRuns(
|
|
361
|
-
conn:
|
|
355
|
+
conn: SQLiteConnection,
|
|
362
356
|
taskID: string,
|
|
363
357
|
queue: string
|
|
364
358
|
): Promise<RunRow[]> {
|
|
@@ -387,7 +381,7 @@ async function getRuns(
|
|
|
387
381
|
}
|
|
388
382
|
|
|
389
383
|
async function getRemainingTasksCount(
|
|
390
|
-
conn:
|
|
384
|
+
conn: SQLiteConnection,
|
|
391
385
|
queue: string
|
|
392
386
|
): Promise<number> {
|
|
393
387
|
const { rows } = await conn.query<{ count: number }>(
|
|
@@ -398,7 +392,7 @@ async function getRemainingTasksCount(
|
|
|
398
392
|
}
|
|
399
393
|
|
|
400
394
|
async function getRemainingEventsCount(
|
|
401
|
-
conn:
|
|
395
|
+
conn: SQLiteConnection,
|
|
402
396
|
queue: string
|
|
403
397
|
): Promise<number> {
|
|
404
398
|
const { rows } = await conn.query<{ count: number }>(
|
|
@@ -409,7 +403,7 @@ async function getRemainingEventsCount(
|
|
|
409
403
|
}
|
|
410
404
|
|
|
411
405
|
async function getWaitsCount(
|
|
412
|
-
conn:
|
|
406
|
+
conn: SQLiteConnection,
|
|
413
407
|
queue: string
|
|
414
408
|
): Promise<number> {
|
|
415
409
|
const { rows } = await conn.query<{ count: number }>(
|
|
@@ -420,7 +414,7 @@ async function getWaitsCount(
|
|
|
420
414
|
}
|
|
421
415
|
|
|
422
416
|
async function getCheckpoint(
|
|
423
|
-
conn:
|
|
417
|
+
conn: SQLiteConnection,
|
|
424
418
|
taskID: string,
|
|
425
419
|
checkpointName: string,
|
|
426
420
|
queue: string
|
|
@@ -447,7 +441,7 @@ async function getCheckpoint(
|
|
|
447
441
|
}
|
|
448
442
|
|
|
449
443
|
async function scheduleRun(
|
|
450
|
-
conn:
|
|
444
|
+
conn: SQLiteConnection,
|
|
451
445
|
runID: string,
|
|
452
446
|
wakeAt: Date,
|
|
453
447
|
queue: string
|
|
@@ -460,7 +454,7 @@ async function scheduleRun(
|
|
|
460
454
|
}
|
|
461
455
|
|
|
462
456
|
async function completeRun(
|
|
463
|
-
conn:
|
|
457
|
+
conn: SQLiteConnection,
|
|
464
458
|
runID: string,
|
|
465
459
|
payload: JsonValue,
|
|
466
460
|
queue: string
|
|
@@ -473,7 +467,7 @@ async function completeRun(
|
|
|
473
467
|
}
|
|
474
468
|
|
|
475
469
|
async function cleanupTasksByTTL(
|
|
476
|
-
conn:
|
|
470
|
+
conn: SQLiteConnection,
|
|
477
471
|
ttlSeconds: number,
|
|
478
472
|
limit: number,
|
|
479
473
|
queue: string
|
|
@@ -486,7 +480,7 @@ async function cleanupTasksByTTL(
|
|
|
486
480
|
}
|
|
487
481
|
|
|
488
482
|
async function cleanupEventsByTTL(
|
|
489
|
-
conn:
|
|
483
|
+
conn: SQLiteConnection,
|
|
490
484
|
ttlSeconds: number,
|
|
491
485
|
limit: number,
|
|
492
486
|
queue: string
|
|
@@ -499,7 +493,7 @@ async function cleanupEventsByTTL(
|
|
|
499
493
|
}
|
|
500
494
|
|
|
501
495
|
async function setTaskCheckpointState(
|
|
502
|
-
conn:
|
|
496
|
+
conn: SQLiteConnection,
|
|
503
497
|
taskID: string,
|
|
504
498
|
stepName: string,
|
|
505
499
|
state: JsonValue,
|
|
@@ -521,7 +515,7 @@ async function setTaskCheckpointState(
|
|
|
521
515
|
}
|
|
522
516
|
|
|
523
517
|
async function awaitEventInternal(
|
|
524
|
-
conn:
|
|
518
|
+
conn: SQLiteConnection,
|
|
525
519
|
taskID: string,
|
|
526
520
|
runID: string,
|
|
527
521
|
stepName: string,
|
|
@@ -537,7 +531,7 @@ async function awaitEventInternal(
|
|
|
537
531
|
}
|
|
538
532
|
|
|
539
533
|
async function extendClaim(
|
|
540
|
-
conn:
|
|
534
|
+
conn: SQLiteConnection,
|
|
541
535
|
runID: string,
|
|
542
536
|
extendBySeconds: number,
|
|
543
537
|
queue: string
|
package/test/sqlite.test.ts
CHANGED
|
@@ -4,13 +4,14 @@ import { mkdtempSync, rmSync } from "node:fs";
|
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { tmpdir } from "node:os";
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { SQLiteConnection } from "../src/sqlite-connection";
|
|
8
8
|
import type { SQLiteDatabase } from "../src/sqlite-types";
|
|
9
|
+
import { Temporal } from "../src/index";
|
|
9
10
|
|
|
10
|
-
describe("
|
|
11
|
+
describe("SQLiteConnection", () => {
|
|
11
12
|
it("rewrites postgres-style params and absurd schema names", async () => {
|
|
12
|
-
const db = new sqlite(":memory:") as
|
|
13
|
-
const conn = new
|
|
13
|
+
const db = new sqlite(":memory:") as SQLiteDatabase;
|
|
14
|
+
const conn = new SQLiteConnection(db);
|
|
14
15
|
|
|
15
16
|
await conn.exec("CREATE TABLE absurd_tasks (id, name)");
|
|
16
17
|
await conn.exec("INSERT INTO absurd.tasks (id, name) VALUES ($1, $2)", [
|
|
@@ -28,8 +29,8 @@ describe("SqliteConnection", () => {
|
|
|
28
29
|
});
|
|
29
30
|
|
|
30
31
|
it("throws when query is used for non-reader statements", async () => {
|
|
31
|
-
const db = new sqlite(":memory:") as
|
|
32
|
-
const conn = new
|
|
32
|
+
const db = new sqlite(":memory:") as SQLiteDatabase;
|
|
33
|
+
const conn = new SQLiteConnection(db);
|
|
33
34
|
|
|
34
35
|
await expect(conn.query("CREATE TABLE t (id)")).rejects.toThrow(
|
|
35
36
|
"only statements that return data"
|
|
@@ -38,8 +39,8 @@ describe("SqliteConnection", () => {
|
|
|
38
39
|
});
|
|
39
40
|
|
|
40
41
|
it("decodes JSON from typeless columns", async () => {
|
|
41
|
-
const db = new sqlite(":memory:") as
|
|
42
|
-
const conn = new
|
|
42
|
+
const db = new sqlite(":memory:") as SQLiteDatabase;
|
|
43
|
+
const conn = new SQLiteConnection(db);
|
|
43
44
|
|
|
44
45
|
await conn.exec("CREATE TABLE t (payload)");
|
|
45
46
|
await conn.exec("INSERT INTO t (payload) VALUES ($1)", ['{"a":1}']);
|
|
@@ -53,8 +54,8 @@ describe("SqliteConnection", () => {
|
|
|
53
54
|
});
|
|
54
55
|
|
|
55
56
|
it("decodes JSON from blob columns", async () => {
|
|
56
|
-
const db = new sqlite(":memory:") as
|
|
57
|
-
const conn = new
|
|
57
|
+
const db = new sqlite(":memory:") as SQLiteDatabase;
|
|
58
|
+
const conn = new SQLiteConnection(db);
|
|
58
59
|
|
|
59
60
|
await conn.exec("CREATE TABLE t_blob (payload BLOB)");
|
|
60
61
|
await conn.exec("INSERT INTO t_blob (payload) VALUES ($1)", [
|
|
@@ -69,29 +70,59 @@ describe("SqliteConnection", () => {
|
|
|
69
70
|
db.close();
|
|
70
71
|
});
|
|
71
72
|
|
|
72
|
-
it("decodes datetime columns into
|
|
73
|
-
const db = new sqlite(":memory:") as
|
|
74
|
-
const conn = new
|
|
73
|
+
it("decodes datetime columns into Temporal.Instant objects", async () => {
|
|
74
|
+
const db = new sqlite(":memory:") as SQLiteDatabase;
|
|
75
|
+
const conn = new SQLiteConnection(db);
|
|
75
76
|
const now = Date.now();
|
|
76
77
|
|
|
77
78
|
await conn.exec("CREATE TABLE t_date (created_at DATETIME)");
|
|
78
79
|
await conn.exec("INSERT INTO t_date (created_at) VALUES ($1)", [now]);
|
|
79
80
|
|
|
80
|
-
const { rows } = await conn.query<{ created_at:
|
|
81
|
+
const { rows } = await conn.query<{ created_at: Temporal.Instant }>(
|
|
81
82
|
"SELECT created_at FROM t_date"
|
|
82
83
|
);
|
|
83
84
|
|
|
84
|
-
expect(rows[0]?.created_at).toBeInstanceOf(
|
|
85
|
-
expect(rows[0]?.created_at.
|
|
85
|
+
expect(rows[0]?.created_at).toBeInstanceOf(Temporal.Instant);
|
|
86
|
+
expect(rows[0]?.created_at.epochMilliseconds).toBe(now);
|
|
87
|
+
db.close();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("allows custom value codec overrides", async () => {
|
|
91
|
+
const db = new sqlite(":memory:") as SQLiteDatabase;
|
|
92
|
+
const encodedValues: unknown[] = [];
|
|
93
|
+
const conn = new SQLiteConnection(db, {
|
|
94
|
+
valueCodec: {
|
|
95
|
+
encodeParam: (value) => {
|
|
96
|
+
encodedValues.push(value);
|
|
97
|
+
return value;
|
|
98
|
+
},
|
|
99
|
+
decodeColumn: ({ value }) => {
|
|
100
|
+
if (typeof value === "string") {
|
|
101
|
+
return value.toUpperCase();
|
|
102
|
+
}
|
|
103
|
+
return value;
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
await conn.exec("CREATE TABLE t (name TEXT)");
|
|
109
|
+
await conn.exec("INSERT INTO t (name) VALUES ($1)", ["alpha"]);
|
|
110
|
+
|
|
111
|
+
const { rows } = await conn.query<{ name: string }>(
|
|
112
|
+
"SELECT name FROM t"
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
expect(encodedValues).toEqual(["alpha"]);
|
|
116
|
+
expect(rows[0]?.name).toBe("ALPHA");
|
|
86
117
|
db.close();
|
|
87
118
|
});
|
|
88
119
|
|
|
89
120
|
it("retries when SQLite reports the database is busy", async () => {
|
|
90
121
|
const tempDir = mkdtempSync(join(tmpdir(), "absurd-sqlite-busy-"));
|
|
91
122
|
const dbPath = join(tempDir, "busy.db");
|
|
92
|
-
const primary = new sqlite(dbPath) as
|
|
123
|
+
const primary = new sqlite(dbPath) as SQLiteDatabase;
|
|
93
124
|
(primary as any).pragma("busy_timeout = 1");
|
|
94
|
-
const conn = new
|
|
125
|
+
const conn = new SQLiteConnection(primary);
|
|
95
126
|
await conn.exec("CREATE TABLE t_busy (id INTEGER PRIMARY KEY, value TEXT)");
|
|
96
127
|
|
|
97
128
|
const blocker = new sqlite(dbPath);
|
|
@@ -150,7 +181,7 @@ describe("SqliteConnection", () => {
|
|
|
150
181
|
close: vi.fn(),
|
|
151
182
|
loadExtension: vi.fn(),
|
|
152
183
|
};
|
|
153
|
-
const conn = new
|
|
184
|
+
const conn = new SQLiteConnection(db);
|
|
154
185
|
|
|
155
186
|
await expect(
|
|
156
187
|
conn.exec("UPDATE locked_table SET value = $1 WHERE id = $2", [1, 1])
|
package/test/step.test.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, test, expect, beforeAll, afterEach, vi } from "vitest";
|
|
2
2
|
import { createTestAbsurd, randomName, type TestContext } from "./setup.js";
|
|
3
|
-
import type
|
|
3
|
+
import { Temporal, type Absurd } from "../src/index.js";
|
|
4
4
|
|
|
5
5
|
describe("Step functionality", () => {
|
|
6
6
|
let ctx: TestContext;
|
|
@@ -193,7 +193,7 @@ describe("Step functionality", () => {
|
|
|
193
193
|
|
|
194
194
|
const durationSeconds = 60;
|
|
195
195
|
absurd.registerTask({ name: "sleep-for" }, async (_params, ctx) => {
|
|
196
|
-
await ctx.sleepFor("wait-for", durationSeconds);
|
|
196
|
+
await ctx.sleepFor("wait-for", Temporal.Duration.from({ seconds: durationSeconds }));
|
|
197
197
|
return { resumed: true };
|
|
198
198
|
});
|
|
199
199
|
|
|
@@ -205,7 +205,7 @@ describe("Step functionality", () => {
|
|
|
205
205
|
state: "sleeping",
|
|
206
206
|
});
|
|
207
207
|
const wakeTime = new Date(base.getTime() + durationSeconds * 1000);
|
|
208
|
-
expect(sleepingRun?.available_at?.
|
|
208
|
+
expect(sleepingRun?.available_at?.epochMilliseconds).toBe(wakeTime.getTime());
|
|
209
209
|
|
|
210
210
|
const resumeTime = new Date(wakeTime.getTime() + 5 * 1000);
|
|
211
211
|
vi.setSystemTime(resumeTime);
|
|
@@ -225,11 +225,12 @@ describe("Step functionality", () => {
|
|
|
225
225
|
await ctx.setFakeNow(base);
|
|
226
226
|
|
|
227
227
|
const wakeTime = new Date(base.getTime() + 5 * 60 * 1000);
|
|
228
|
+
const wakeInstant = Temporal.Instant.fromEpochMilliseconds(wakeTime.getTime());
|
|
228
229
|
let executions = 0;
|
|
229
230
|
|
|
230
231
|
absurd.registerTask({ name: "sleep-until" }, async (_params, ctx) => {
|
|
231
232
|
executions++;
|
|
232
|
-
await ctx.sleepUntil("sleep-step",
|
|
233
|
+
await ctx.sleepUntil("sleep-step", wakeInstant);
|
|
233
234
|
return { executions };
|
|
234
235
|
});
|
|
235
236
|
|
|
@@ -240,7 +241,7 @@ describe("Step functionality", () => {
|
|
|
240
241
|
expect(checkpointRow).toMatchObject({
|
|
241
242
|
checkpoint_name: "sleep-step",
|
|
242
243
|
owner_run_id: runID,
|
|
243
|
-
state:
|
|
244
|
+
state: wakeInstant.toString(),
|
|
244
245
|
});
|
|
245
246
|
|
|
246
247
|
const sleepingRun = await ctx.getRun(runID);
|
package/dist/absurd-types.d.ts
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import type { ClaimedTask, JsonValue, SpawnOptions, SpawnResult, TaskHandler, TaskRegistrationOptions, WorkerOptions } from "absurd-sdk";
|
|
2
|
-
import type { SQLiteRestBindParams } from "./sqlite-types";
|
|
3
|
-
/**
|
|
4
|
-
* Minimal query interface compatible with Absurd's database operations.
|
|
5
|
-
*/
|
|
6
|
-
export interface Queryable {
|
|
7
|
-
/**
|
|
8
|
-
* Execute a parameterized SQL query and return rows.
|
|
9
|
-
* @param sql SQL text with parameter placeholders.
|
|
10
|
-
* @param params Optional positional parameters.
|
|
11
|
-
*/
|
|
12
|
-
query<R extends object = Record<string, any>>(sql: string, params?: SQLiteRestBindParams): Promise<{
|
|
13
|
-
rows: R[];
|
|
14
|
-
}>;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Background worker handle returned by startWorker().
|
|
18
|
-
*/
|
|
19
|
-
export interface Worker {
|
|
20
|
-
/**
|
|
21
|
-
* Stop the worker loop and wait for in-flight tasks to settle.
|
|
22
|
-
*/
|
|
23
|
-
close(): Promise<void>;
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Absurd client interface.
|
|
27
|
-
*/
|
|
28
|
-
export interface AbsurdClient {
|
|
29
|
-
/**
|
|
30
|
-
* Create a new client bound to the provided connection.
|
|
31
|
-
* @param con Connection to use for queries.
|
|
32
|
-
* @param owned If true, close the connection when close() is called.
|
|
33
|
-
*/
|
|
34
|
-
/**
|
|
35
|
-
* Register a task handler.
|
|
36
|
-
* @param options Task registration options.
|
|
37
|
-
* @param handler Async task handler.
|
|
38
|
-
*/
|
|
39
|
-
registerTask<P = any, R = any>(options: TaskRegistrationOptions, handler: TaskHandler<P, R>): void;
|
|
40
|
-
/**
|
|
41
|
-
* Create a queue.
|
|
42
|
-
* @param queueName Optional queue name (defaults to client queue).
|
|
43
|
-
*/
|
|
44
|
-
createQueue(queueName?: string): Promise<void>;
|
|
45
|
-
/**
|
|
46
|
-
* Drop a queue.
|
|
47
|
-
* @param queueName Optional queue name (defaults to client queue).
|
|
48
|
-
*/
|
|
49
|
-
dropQueue(queueName?: string): Promise<void>;
|
|
50
|
-
/**
|
|
51
|
-
* List available queues.
|
|
52
|
-
*/
|
|
53
|
-
listQueues(): Promise<Array<string>>;
|
|
54
|
-
/**
|
|
55
|
-
* Spawn a task execution.
|
|
56
|
-
* @param taskName Task name.
|
|
57
|
-
* @param params Task parameters.
|
|
58
|
-
* @param options Spawn options including queue and retry behavior.
|
|
59
|
-
*/
|
|
60
|
-
spawn<P = any>(taskName: string, params: P, options?: SpawnOptions): Promise<SpawnResult>;
|
|
61
|
-
/**
|
|
62
|
-
* Emit an event on a queue.
|
|
63
|
-
* @param eventName Non-empty event name.
|
|
64
|
-
* @param payload Optional JSON payload.
|
|
65
|
-
* @param queueName Optional queue name (defaults to client queue).
|
|
66
|
-
*/
|
|
67
|
-
emitEvent(eventName: string, payload?: JsonValue, queueName?: string): Promise<void>;
|
|
68
|
-
/**
|
|
69
|
-
* Cancel a task by ID.
|
|
70
|
-
* @param taskID Task identifier.
|
|
71
|
-
* @param queueName Optional queue name (defaults to client queue).
|
|
72
|
-
*/
|
|
73
|
-
cancelTask(taskID: string, queueName?: string): Promise<void>;
|
|
74
|
-
/**
|
|
75
|
-
* Claim tasks for processing.
|
|
76
|
-
* @param options Claiming options.
|
|
77
|
-
*/
|
|
78
|
-
claimTasks(options?: {
|
|
79
|
-
batchSize?: number;
|
|
80
|
-
claimTimeout?: number;
|
|
81
|
-
workerId?: string;
|
|
82
|
-
}): Promise<ClaimedTask[]>;
|
|
83
|
-
/**
|
|
84
|
-
* Claim and process a batch of tasks sequentially.
|
|
85
|
-
* @param workerId Worker identifier.
|
|
86
|
-
* @param claimTimeout Lease duration in seconds.
|
|
87
|
-
* @param batchSize Max tasks to process.
|
|
88
|
-
*/
|
|
89
|
-
workBatch(workerId?: string, claimTimeout?: number, batchSize?: number): Promise<void>;
|
|
90
|
-
/**
|
|
91
|
-
* Start a background worker that polls and executes tasks.
|
|
92
|
-
* @param options Worker behavior options.
|
|
93
|
-
*/
|
|
94
|
-
startWorker(options?: WorkerOptions): Promise<Worker>;
|
|
95
|
-
/**
|
|
96
|
-
* Close the client and any owned resources.
|
|
97
|
-
*/
|
|
98
|
-
close(): Promise<void>;
|
|
99
|
-
/**
|
|
100
|
-
* Execute a claimed task (used by workers).
|
|
101
|
-
* @param task Claimed task record.
|
|
102
|
-
* @param claimTimeout Lease duration in seconds.
|
|
103
|
-
* @param options Execution options.
|
|
104
|
-
*/
|
|
105
|
-
executeTask(task: ClaimedTask, claimTimeout: number, options?: {
|
|
106
|
-
fatalOnLeaseTimeout?: boolean;
|
|
107
|
-
}): Promise<void>;
|
|
108
|
-
}
|
|
109
|
-
//# sourceMappingURL=absurd-types.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"absurd-types.d.ts","sourceRoot":"","sources":["../src/absurd-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,SAAS,EACT,YAAY,EACZ,WAAW,EACX,WAAW,EACX,uBAAuB,EACvB,aAAa,EACd,MAAM,YAAY,CAAC;AAEpB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAE3D;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB;;;;OAIG;IACH,KAAK,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC1C,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,oBAAoB,GAC5B,OAAO,CAAC;QAAE,IAAI,EAAE,CAAC,EAAE,CAAA;KAAE,CAAC,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,MAAM;IACrB;;OAEG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IAGH;;;;OAIG;IACH,YAAY,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,GAAG,EAC3B,OAAO,EAAE,uBAAuB,EAChC,OAAO,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,GACzB,IAAI,CAAC;IAER;;;OAGG;IACH,WAAW,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C;;;OAGG;IACH,SAAS,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C;;OAEG;IACH,UAAU,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IAErC;;;;;OAKG;IACH,KAAK,CAAC,CAAC,GAAG,GAAG,EACX,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,CAAC,EACT,OAAO,CAAC,EAAE,YAAY,GACrB,OAAO,CAAC,WAAW,CAAC,CAAC;IAExB;;;;;OAKG;IACH,SAAS,CACP,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,SAAS,EACnB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjB;;;;OAIG;IACH,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9D;;;OAGG;IACH,UAAU,CAAC,OAAO,CAAC,EAAE;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAE3B;;;;;OAKG;IACH,SAAS,CACP,QAAQ,CAAC,EAAE,MAAM,EACjB,YAAY,CAAC,EAAE,MAAM,EACrB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjB;;;OAGG;IACH,WAAW,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAEtD;;OAEG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB;;;;;OAKG;IACH,WAAW,CACT,IAAI,EAAE,WAAW,EACjB,YAAY,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE;QAAE,mBAAmB,CAAC,EAAE,OAAO,CAAA;KAAE,GAC1C,OAAO,CAAC,IAAI,CAAC,CAAC;CAClB"}
|
package/dist/absurd-types.js
DELETED
package/dist/absurd-types.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"absurd-types.js","sourceRoot":"","sources":["../src/absurd-types.ts"],"names":[],"mappings":""}
|
package/dist/cjs/absurd-types.js
DELETED
package/dist/sqlite.d.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { Queryable } from "./absurd-types";
|
|
2
|
-
import type { SQLiteRestBindParams, SQLiteDatabase } from "./sqlite-types";
|
|
3
|
-
export declare class SqliteConnection implements Queryable {
|
|
4
|
-
private readonly db;
|
|
5
|
-
private readonly maxRetries;
|
|
6
|
-
private readonly baseRetryDelayMs;
|
|
7
|
-
constructor(db: SQLiteDatabase);
|
|
8
|
-
query<R extends object = Record<string, any>>(sql: string, params?: SQLiteRestBindParams): Promise<{
|
|
9
|
-
rows: R[];
|
|
10
|
-
}>;
|
|
11
|
-
exec(sql: string, params?: SQLiteRestBindParams): Promise<void>;
|
|
12
|
-
private runWithRetry;
|
|
13
|
-
}
|
|
14
|
-
//# sourceMappingURL=sqlite.d.ts.map
|
package/dist/sqlite.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite.d.ts","sourceRoot":"","sources":["../src/sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EACV,oBAAoB,EACpB,cAAc,EAGf,MAAM,gBAAgB,CAAC;AAExB,qBAAa,gBAAiB,YAAW,SAAS;IAChD,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAiB;IACpC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAK;IAChC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAM;gBAE3B,EAAE,EAAE,cAAc;IAKxB,KAAK,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAChD,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,oBAAoB,GAC5B,OAAO,CAAC;QAAE,IAAI,EAAE,CAAC,EAAE,CAAA;KAAE,CAAC;IAoBnB,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;YAQvD,YAAY;CAc3B"}
|
package/dist/sqlite.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite.js","sourceRoot":"","sources":["../src/sqlite.ts"],"names":[],"mappings":"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"}
|