cairnq 0.1.0 → 0.3.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/README.md +28 -0
- package/dist/_protocol/migrations/postgres/0001_init.sql +3 -1
- package/dist/_protocol/migrations/postgres/0002_purge_index.sql +6 -0
- package/dist/_protocol/migrations/postgres/0003_notify.sql +38 -0
- package/dist/_protocol/migrations/postgres/0004_lease_index.sql +16 -0
- package/dist/_protocol/migrations/postgres/0005_clear_terminal_lease.sql +17 -0
- package/dist/_protocol/migrations/sqlite/0001_init.sql +3 -1
- package/dist/_protocol/migrations/sqlite/0002_purge_index.sql +6 -0
- package/dist/_protocol/migrations/sqlite/0004_lease_index.sql +22 -0
- package/dist/_protocol/migrations/sqlite/0005_clear_terminal_lease.sql +17 -0
- package/dist/_protocol/sql/postgres/claim.sql +18 -5
- package/dist/_protocol/sql/postgres/claim_one_queue.sql +35 -0
- package/dist/_protocol/sql/postgres/complete.sql +3 -0
- package/dist/_protocol/sql/postgres/fail.sql +30 -8
- package/dist/_protocol/sql/postgres/insert_task.sql +6 -3
- package/dist/_protocol/sql/postgres/list.sql +3 -1
- package/dist/_protocol/sql/postgres/lock_key.sql +9 -0
- package/dist/_protocol/sql/postgres/progress.sql +4 -3
- package/dist/_protocol/sql/postgres/protocol_version.sql +4 -0
- package/dist/_protocol/sql/postgres/purge.sql +25 -0
- package/dist/_protocol/sql/postgres/recover_leases.sql +49 -14
- package/dist/_protocol/sql/postgres/retry.sql +3 -0
- package/dist/_protocol/sql/postgres/stats.sql +8 -0
- package/dist/_protocol/sql/postgres/succeed.sql +4 -0
- package/dist/_protocol/sql/sqlite/claim.sql +13 -2
- package/dist/_protocol/sql/sqlite/claim_one_queue.sql +36 -0
- package/dist/_protocol/sql/sqlite/claimable_probe.sql +6 -2
- package/dist/_protocol/sql/sqlite/complete.sql +3 -0
- package/dist/_protocol/sql/sqlite/fail.sql +32 -8
- package/dist/_protocol/sql/sqlite/list.sql +3 -1
- package/dist/_protocol/sql/sqlite/lock_key.sql +5 -0
- package/dist/_protocol/sql/sqlite/progress.sql +6 -2
- package/dist/_protocol/sql/sqlite/protocol_version.sql +4 -0
- package/dist/_protocol/sql/sqlite/purge.sql +18 -0
- package/dist/_protocol/sql/sqlite/recover_leases.sql +25 -7
- package/dist/_protocol/sql/sqlite/retry.sql +3 -0
- package/dist/_protocol/sql/sqlite/stats.sql +8 -0
- package/dist/_protocol/sql/sqlite/succeed.sql +4 -0
- package/dist/client.d.ts +10 -2
- package/dist/client.js +12 -0
- package/dist/context.d.ts +17 -1
- package/dist/context.js +60 -6
- package/dist/errors.d.ts +18 -2
- package/dist/errors.js +49 -3
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -1
- package/dist/sql.js +16 -9
- package/dist/store/base.d.ts +114 -9
- package/dist/store/base.js +376 -1
- package/dist/store/postgres.d.ts +62 -63
- package/dist/store/postgres.js +245 -222
- package/dist/store/sqlite.d.ts +83 -60
- package/dist/store/sqlite.js +370 -234
- package/dist/wait.d.ts +15 -2
- package/dist/wait.js +23 -5
- package/dist/worker.d.ts +53 -1
- package/dist/worker.js +202 -42
- package/package.json +9 -2
- package/src/client.ts +16 -2
- package/src/context.ts +70 -13
- package/src/errors.ts +59 -4
- package/src/index.ts +3 -1
- package/src/sql.ts +15 -8
- package/src/store/base.ts +443 -27
- package/src/store/postgres.ts +243 -267
- package/src/store/sqlite.ts +378 -263
- package/src/wait.ts +28 -5
- package/src/worker.ts +242 -42
package/dist/store/postgres.d.ts
CHANGED
|
@@ -1,29 +1,62 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
import type { ListInput, SubmitInput, TaskStore } from "./base.js";
|
|
1
|
+
import { type Fetch, type Params, TaskStore } from "./base.js";
|
|
3
2
|
/**
|
|
4
|
-
*
|
|
3
|
+
* The rewritten SQL and the order its `$n` slots must be filled in.
|
|
4
|
+
*
|
|
5
|
+
* Translates the protocol's named-parameter SQL (`:name`) into Postgres positional
|
|
5
6
|
* placeholders (`$1`), collapsing each DISTINCT name to ONE slot — statements reuse
|
|
6
|
-
* a name across CASE branches / IS NULL guards (e.g. list.sql).
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* a name across CASE branches / IS NULL guards (e.g. list.sql). Which names count
|
|
8
|
+
* as parameters is `statementParams`' decision, shared with the SQLite binding path
|
|
9
|
+
* so the two can't disagree about, say, a `::type` cast.
|
|
10
|
+
*
|
|
11
|
+
* Memoized on the statement text, which is loaded once and never varies: this runs
|
|
12
|
+
* on every query, including the worker's poll loop, for a result that cannot have
|
|
13
|
+
* changed. Exported for unit testing.
|
|
9
14
|
*/
|
|
10
|
-
export declare function
|
|
15
|
+
export declare function positionalStatement(sql: string): {
|
|
16
|
+
text: string;
|
|
17
|
+
order: readonly string[];
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* The statement's rewritten text plus this call's values, in slot order. Names the
|
|
21
|
+
* statement does not use are simply not bound, so callers may pass a superset.
|
|
22
|
+
*/
|
|
23
|
+
export declare function toPositional(sql: string, params: Params): {
|
|
11
24
|
text: string;
|
|
12
25
|
values: unknown[];
|
|
13
26
|
};
|
|
14
27
|
/**
|
|
15
|
-
* PostgresStore —
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
28
|
+
* PostgresStore — the Postgres dialect of the shared cairnq-protocol SQL.
|
|
29
|
+
*
|
|
30
|
+
* Everything protocol-shaped lives in TaskStore; this file is only what Postgres
|
|
31
|
+
* does differently: a `pg` Pool, `:name` -> `$n` translation, and time taken from
|
|
32
|
+
* the DB clock (`now()`) instead of from the SDK, which is what makes this backend
|
|
33
|
+
* multi-host — unlike SQLite it coordinates API and worker processes across
|
|
34
|
+
* machines, with no shared clock to agree on. claim uses FOR UPDATE SKIP LOCKED
|
|
35
|
+
* and needs no claimable_probe, because PG readers don't block writers. JSON
|
|
36
|
+
* columns are jsonb (bound as JSON text, read back as objects by rowToTask).
|
|
20
37
|
*/
|
|
21
|
-
export declare class PostgresStore
|
|
38
|
+
export declare class PostgresStore extends TaskStore {
|
|
22
39
|
private readonly dsn;
|
|
23
40
|
private readonly opts;
|
|
24
41
|
private pool;
|
|
25
42
|
private connecting;
|
|
26
43
|
private readonly statements;
|
|
44
|
+
private listener;
|
|
45
|
+
private listenerConnecting;
|
|
46
|
+
/** LISTEN is off for good: the store was closed, or the server accepted a
|
|
47
|
+
* connection but refused LISTEN (e.g. a transaction-mode pooler) —
|
|
48
|
+
* deterministic, so retrying would fail the same way every time. */
|
|
49
|
+
private listenerUnavailable;
|
|
50
|
+
/** A failure to even connect is transient (network blip, server restarting):
|
|
51
|
+
* retry, but not before this time, backing off so a down server is not
|
|
52
|
+
* hammered from the poll loop. */
|
|
53
|
+
private listenerRetryAt;
|
|
54
|
+
private listenerBackoffMs;
|
|
55
|
+
/** Queues notified while nobody was waiting; consumed by the next claimWake
|
|
56
|
+
* so a wake that lands between polls is not lost. */
|
|
57
|
+
private readonly pendingQueues;
|
|
58
|
+
/** Wake callbacks by key: "queued" (broadcast) or "done:<task id>". */
|
|
59
|
+
private readonly waiters;
|
|
27
60
|
constructor(dsn: string, opts?: {
|
|
28
61
|
max?: number;
|
|
29
62
|
});
|
|
@@ -34,54 +67,20 @@ export declare class PostgresStore implements TaskStore {
|
|
|
34
67
|
private applyMigrations;
|
|
35
68
|
private readProtocolVersion;
|
|
36
69
|
protocolVersion(): Promise<number>;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
claim(input: {
|
|
54
|
-
queues: string[];
|
|
55
|
-
workerId: string;
|
|
56
|
-
leaseMs?: number;
|
|
57
|
-
limit?: number;
|
|
58
|
-
}): Promise<Task[]>;
|
|
59
|
-
heartbeat(input: {
|
|
60
|
-
taskId: string;
|
|
61
|
-
workerId: string;
|
|
62
|
-
leaseMs?: number;
|
|
63
|
-
}): Promise<Task>;
|
|
64
|
-
progress(input: {
|
|
65
|
-
taskId: string;
|
|
66
|
-
workerId: string;
|
|
67
|
-
progress: number | null;
|
|
68
|
-
message: string | null;
|
|
69
|
-
}): Promise<Task>;
|
|
70
|
-
succeed(input: {
|
|
71
|
-
taskId: string;
|
|
72
|
-
workerId: string;
|
|
73
|
-
result: unknown;
|
|
74
|
-
}): Promise<Task>;
|
|
75
|
-
complete(input: {
|
|
76
|
-
taskId: string;
|
|
77
|
-
workerId: string;
|
|
78
|
-
result: unknown;
|
|
79
|
-
}): Promise<Task>;
|
|
80
|
-
fail(input: {
|
|
81
|
-
taskId: string;
|
|
82
|
-
workerId: string;
|
|
83
|
-
error: unknown;
|
|
84
|
-
retryable?: boolean;
|
|
85
|
-
delayMs?: number;
|
|
86
|
-
}): Promise<Task>;
|
|
70
|
+
claimWake(queues: string[], timeoutMs: number): Promise<void>;
|
|
71
|
+
taskDoneWake(taskId: string, timeoutMs: number): Promise<void>;
|
|
72
|
+
/** A promise resolving on notification-or-timeout, deregistering either way.
|
|
73
|
+
* The timer is unref'd: while a listener exists its socket keeps the process
|
|
74
|
+
* alive, and dropListener wakes every waiter the moment it goes away. */
|
|
75
|
+
private wakeOn;
|
|
76
|
+
/** True once the LISTEN connection is up; starts connecting it otherwise
|
|
77
|
+
* (respecting the transient-failure backoff). Callers fall back to plain
|
|
78
|
+
* polling until it is ready (or forever, if it can't be established) —
|
|
79
|
+
* correctness never depends on it. */
|
|
80
|
+
private listenerReady;
|
|
81
|
+
private startListener;
|
|
82
|
+
private onNotification;
|
|
83
|
+
private dropListener;
|
|
84
|
+
protected fetch(name: string, params: Params): Promise<any[]>;
|
|
85
|
+
protected tx<T>(fn: (fetch: Fetch) => Promise<T>): Promise<T>;
|
|
87
86
|
}
|