@zizq-labs/zizq 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 +86 -0
- package/dist/client.d.ts +747 -0
- package/dist/client.js +902 -0
- package/dist/enqueue.d.ts +119 -0
- package/dist/enqueue.js +110 -0
- package/dist/handler.d.ts +179 -0
- package/dist/handler.js +45 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +8 -0
- package/dist/query.d.ts +372 -0
- package/dist/query.js +653 -0
- package/dist/resources.d.ts +281 -0
- package/dist/resources.js +319 -0
- package/dist/unique-key.d.ts +58 -0
- package/dist/unique-key.js +122 -0
- package/dist/worker.d.ts +307 -0
- package/dist/worker.js +396 -0
- package/package.json +34 -0
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,747 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Low-level HTTP client for the Zizq job queue server.
|
|
3
|
+
*
|
|
4
|
+
* @example Basic usage
|
|
5
|
+
* ```ts
|
|
6
|
+
* import { Client } from "@zizq-labs/zizq";
|
|
7
|
+
*
|
|
8
|
+
* const client = new Client({ url: "http://localhost:7890" });
|
|
9
|
+
*
|
|
10
|
+
* // Enqueue a job
|
|
11
|
+
* const job = await client.enqueue({
|
|
12
|
+
* type: "send_email",
|
|
13
|
+
* queue: "emails",
|
|
14
|
+
* payload: { to: "user@example.com", subject: "Hello" },
|
|
15
|
+
* });
|
|
16
|
+
* console.log(job.id); // "03fvqh..."
|
|
17
|
+
*
|
|
18
|
+
* // Take and process jobs (streaming)
|
|
19
|
+
* for await (const job of client.take({ prefetch: 5, queues: ["emails"] })) {
|
|
20
|
+
* try {
|
|
21
|
+
* await processJob(job);
|
|
22
|
+
* await client.reportSuccess(job.id);
|
|
23
|
+
* } catch (err) {
|
|
24
|
+
* await client.reportFailure(job.id, { message: err.message });
|
|
25
|
+
* }
|
|
26
|
+
* }
|
|
27
|
+
*
|
|
28
|
+
* await client.close();
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* @module
|
|
32
|
+
*/
|
|
33
|
+
import { type Dispatcher } from "undici";
|
|
34
|
+
import { Job, JobPage, ErrorRecord, ErrorPage } from "./resources.ts";
|
|
35
|
+
import { JobQuery, type JobQueryOptions } from "./query.ts";
|
|
36
|
+
/** Lifecycle status of a job. */
|
|
37
|
+
export type JobStatus = "ready" | "in_flight" | "scheduled" | "completed" | "dead";
|
|
38
|
+
/** Sort direction for paginated listings. */
|
|
39
|
+
export type SortDirection = "asc" | "desc";
|
|
40
|
+
/** Uniqueness scope for deduplication. */
|
|
41
|
+
export type UniqueScope = "queued" | "active" | "exists";
|
|
42
|
+
export { Job, JobPage, ErrorRecord, ErrorPage, type JobData, type ErrorRecordData } from "./resources.ts";
|
|
43
|
+
/**
|
|
44
|
+
* Backoff configuration for retry delays.
|
|
45
|
+
*
|
|
46
|
+
* This is used in the following formula:
|
|
47
|
+
*
|
|
48
|
+
* ```
|
|
49
|
+
* t = baseMs + (attempts ** exponent) + (attempts * random() * jitterMs)
|
|
50
|
+
* ```
|
|
51
|
+
*
|
|
52
|
+
* The random jitter is designed to ensure clusters of failed jobs do not all
|
|
53
|
+
* retry at the same time but are instead randomly spread out.
|
|
54
|
+
*/
|
|
55
|
+
export interface BackoffConfig {
|
|
56
|
+
/** Base delay in milliseconds, applied to all retries. */
|
|
57
|
+
baseMs: number;
|
|
58
|
+
/** Backoff curve steepness (attempts ** exponent). */
|
|
59
|
+
exponent: number;
|
|
60
|
+
/** Maximum random jitter in milliseconds per attempt multiplier. */
|
|
61
|
+
jitterMs: number;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Retention configuration controlling how long jobs in terminal statuses are kept.
|
|
65
|
+
*
|
|
66
|
+
* The terminal statuses are "completed" and "dead".
|
|
67
|
+
*/
|
|
68
|
+
export interface RetentionConfig {
|
|
69
|
+
/** How long completed jobs remain visible (ms). `null` clears to server default. */
|
|
70
|
+
completedMs?: number | null;
|
|
71
|
+
/** How long dead jobs remain visible (ms). `null` clears to server default. */
|
|
72
|
+
deadMs?: number | null;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Options for enqueueing a single job.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* await client.enqueue({
|
|
80
|
+
* type: "generate_report",
|
|
81
|
+
* queue: "reports",
|
|
82
|
+
* payload: { reportId: 42 },
|
|
83
|
+
* priority: 100, // optional, lower = higher priority
|
|
84
|
+
* readyAt: Date.now() + 60000, // optional, delay by 1 minute
|
|
85
|
+
* });
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
export interface EnqueueOptions {
|
|
89
|
+
/** Job type identifier. */
|
|
90
|
+
type: string;
|
|
91
|
+
/**
|
|
92
|
+
* Target queue name.
|
|
93
|
+
*
|
|
94
|
+
* Must be valid UTF-8 and must not contain any of the following reserved
|
|
95
|
+
* characters: ",", "?", "*", "[", "]", "{", "}", "!".
|
|
96
|
+
*/
|
|
97
|
+
queue: string;
|
|
98
|
+
/**
|
|
99
|
+
* Arbitrary payload delivered to the worker.
|
|
100
|
+
*/
|
|
101
|
+
payload: unknown;
|
|
102
|
+
/**
|
|
103
|
+
* Optional priority (lower = higher priority).
|
|
104
|
+
*
|
|
105
|
+
* Valid range is 0 to 65536. Default: 32768.
|
|
106
|
+
*/
|
|
107
|
+
priority?: number;
|
|
108
|
+
/**
|
|
109
|
+
* Optional timestamp (ms since epoch) when the job becomes eligible.
|
|
110
|
+
*
|
|
111
|
+
* When set to a future timestamp the job is created in the "scheduled"
|
|
112
|
+
* status. Otherwise the job is created in the "ready" status.
|
|
113
|
+
*/
|
|
114
|
+
readyAt?: number;
|
|
115
|
+
/**
|
|
116
|
+
* Optional per-job retry limit.
|
|
117
|
+
*
|
|
118
|
+
* When not set the server default value applies.
|
|
119
|
+
*/
|
|
120
|
+
retryLimit?: number;
|
|
121
|
+
/** Optional per-job backoff configuration. */
|
|
122
|
+
backoff?: BackoffConfig;
|
|
123
|
+
/** Optional per-job retention configuration. */
|
|
124
|
+
retention?: RetentionConfig;
|
|
125
|
+
/**
|
|
126
|
+
* Optional unique key for enqueue-time deduplication.
|
|
127
|
+
*
|
|
128
|
+
* Requires a pro license on the server.
|
|
129
|
+
*
|
|
130
|
+
* The key is global across all queues and job types. Prefix with the job
|
|
131
|
+
* type to make it unique per job type.
|
|
132
|
+
*/
|
|
133
|
+
uniqueKey?: string;
|
|
134
|
+
/**
|
|
135
|
+
* Uniqueness scope. Only valid when `uniqueKey` is set.
|
|
136
|
+
*
|
|
137
|
+
* When set to "queued" other jobs with the same key will not be enqueued as
|
|
138
|
+
* long as this job is in the "scheduled" or "ready" statuses.
|
|
139
|
+
*
|
|
140
|
+
* When set to "active" other jobs with the same key will not be enqueued
|
|
141
|
+
* while this job is in the "scheduled", "ready" or "in_flight" statuses.
|
|
142
|
+
*
|
|
143
|
+
* When set to "exists" other jobs with the same key will not be enqueued
|
|
144
|
+
* for as long as this job remains on the server (i.e. until it is eventually
|
|
145
|
+
* reaped, based on the retention policy).
|
|
146
|
+
*/
|
|
147
|
+
uniqueWhile?: UniqueScope;
|
|
148
|
+
}
|
|
149
|
+
/** Options for reporting a job failure. */
|
|
150
|
+
export interface FailureOptions {
|
|
151
|
+
/** Error message describing what went wrong. */
|
|
152
|
+
message: string;
|
|
153
|
+
/** Optional error class name, e.g. "TimeoutError". */
|
|
154
|
+
errorType?: string;
|
|
155
|
+
/** Optional stack trace from the worker. */
|
|
156
|
+
backtrace?: string;
|
|
157
|
+
/** Optional forced retry time (ms since epoch), bypassing backoff. */
|
|
158
|
+
retryAt?: number;
|
|
159
|
+
/**
|
|
160
|
+
* Kill the job immediately regardless of retry limit.
|
|
161
|
+
*
|
|
162
|
+
* Note: passing false does nothing.
|
|
163
|
+
*/
|
|
164
|
+
kill?: boolean;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Options for the streaming take endpoint.
|
|
168
|
+
*
|
|
169
|
+
* Returns an async generator which never terminates as long as the connection
|
|
170
|
+
* to the server remains open. Clients should use `break` to explicitly
|
|
171
|
+
* disconnect from the endpoint and stop receiving jobs.
|
|
172
|
+
*
|
|
173
|
+
* When no jobs are available, the generator waits until new jobs are enqueued.
|
|
174
|
+
*
|
|
175
|
+
* @example
|
|
176
|
+
* ```ts
|
|
177
|
+
* // Take up to 10 jobs at a time from specific queues
|
|
178
|
+
* for await (const job of client.take({ prefetch: 10, queues: ["emails", "webhooks"] })) {
|
|
179
|
+
* // process job...
|
|
180
|
+
* }
|
|
181
|
+
* ```
|
|
182
|
+
*/
|
|
183
|
+
export interface TakeOptions {
|
|
184
|
+
/**
|
|
185
|
+
* Maximum number of "in_flight", unacknowledged jobs the server will send.
|
|
186
|
+
*
|
|
187
|
+
* The default is 1, meaning the client must acknowledge or fail the job
|
|
188
|
+
* before the server sends the next, and so on.
|
|
189
|
+
*/
|
|
190
|
+
prefetch?: number;
|
|
191
|
+
/** Only take jobs from these queues. Empty means all queues. */
|
|
192
|
+
queues?: string[];
|
|
193
|
+
/** AbortSignal to cancel the streaming connection. */
|
|
194
|
+
signal?: AbortSignal;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Options for listing jobs with cursor-based pagination.
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* ```ts
|
|
201
|
+
* const page = await client.listJobs({
|
|
202
|
+
* queue: "emails",
|
|
203
|
+
* status: ["ready", "in_flight"],
|
|
204
|
+
* limit: 20,
|
|
205
|
+
* });
|
|
206
|
+
* ```
|
|
207
|
+
*/
|
|
208
|
+
export interface ListJobsOptions {
|
|
209
|
+
/** Cursor: start after this job ID (exclusive). */
|
|
210
|
+
from?: string;
|
|
211
|
+
/** Sort order. Default: "asc" (oldest first). */
|
|
212
|
+
order?: SortDirection;
|
|
213
|
+
/** Maximum number of jobs per page (1–2000, default 50). */
|
|
214
|
+
limit?: number;
|
|
215
|
+
/** Filter by status. Accepts a single value or an array. */
|
|
216
|
+
status?: JobStatus | JobStatus[];
|
|
217
|
+
/** Filter by queue name. Accepts a single value or an array. */
|
|
218
|
+
queue?: string | string[];
|
|
219
|
+
/** Filter by job type. Accepts a single value or an array. */
|
|
220
|
+
type?: string | string[];
|
|
221
|
+
/** Filter by job ID. Accepts a single value or an array. */
|
|
222
|
+
id?: string | string[];
|
|
223
|
+
/** jq expression to filter jobs by payload. */
|
|
224
|
+
filter?: string;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Options for listing error records for a job.
|
|
228
|
+
*
|
|
229
|
+
* @example
|
|
230
|
+
* ```ts
|
|
231
|
+
* const page = await client.listErrors("job-id", { order: "desc", limit: 10 });
|
|
232
|
+
* ```
|
|
233
|
+
*/
|
|
234
|
+
export interface ListErrorsOptions {
|
|
235
|
+
/** Cursor: start after this attempt number (exclusive). */
|
|
236
|
+
from?: number;
|
|
237
|
+
/** Sort order. Default: "asc" (oldest first). */
|
|
238
|
+
order?: SortDirection;
|
|
239
|
+
/** Maximum number of error records per page (1–2000, default 50). */
|
|
240
|
+
limit?: number;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Mutable fields for updating a job.
|
|
244
|
+
*
|
|
245
|
+
* Field semantics:
|
|
246
|
+
* - **omitted or `undefined`** — leave unchanged
|
|
247
|
+
* - **`null`** — clear the field (only valid for nullable fields)
|
|
248
|
+
* - **a value** — update to that value
|
|
249
|
+
*
|
|
250
|
+
* Nullable fields: `readyAt`, `retryLimit`, `backoff`, `retention`.
|
|
251
|
+
* Non-nullable fields: `queue`, `priority`.
|
|
252
|
+
*
|
|
253
|
+
* @example
|
|
254
|
+
* ```ts
|
|
255
|
+
* // Change priority and clear retry limit (use server default)
|
|
256
|
+
* await client.updateJob("job-id", {
|
|
257
|
+
* priority: 100,
|
|
258
|
+
* retryLimit: null,
|
|
259
|
+
* });
|
|
260
|
+
* ```
|
|
261
|
+
*/
|
|
262
|
+
export interface UpdateJobOptions {
|
|
263
|
+
/** Move the job to a different queue. */
|
|
264
|
+
queue?: string;
|
|
265
|
+
/** Change the job's priority. */
|
|
266
|
+
priority?: number;
|
|
267
|
+
/** Change when the job becomes ready (ms since epoch). `null` clears to immediately ready. */
|
|
268
|
+
readyAt?: number | null;
|
|
269
|
+
/** Override the retry limit. `null` clears to server default. */
|
|
270
|
+
retryLimit?: number | null;
|
|
271
|
+
/** Override the backoff config. `null` clears to server default. */
|
|
272
|
+
backoff?: BackoffConfig | null;
|
|
273
|
+
/** Override the retention config. `null` clears to server default. */
|
|
274
|
+
retention?: RetentionConfig | null;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Options for bulk-updating jobs.
|
|
278
|
+
*
|
|
279
|
+
* Has two parts:
|
|
280
|
+
* - `where` — filter selecting which jobs to update (same as `deleteAllJobs`)
|
|
281
|
+
* - `apply` — fields to update on the matching jobs (same as `updateJob`)
|
|
282
|
+
*
|
|
283
|
+
* An empty array filter (e.g. `where.id: []`) short-circuits to 0 jobs updated.
|
|
284
|
+
*
|
|
285
|
+
* @example
|
|
286
|
+
* ```ts
|
|
287
|
+
* // Lower the priority of all dead jobs in the emails queue
|
|
288
|
+
* const count = await client.updateAllJobs({
|
|
289
|
+
* where: { queue: "emails", status: "dead" },
|
|
290
|
+
* apply: { priority: 1000 },
|
|
291
|
+
* });
|
|
292
|
+
* ```
|
|
293
|
+
*/
|
|
294
|
+
export interface UpdateAllJobsOptions {
|
|
295
|
+
/** Filter selecting which jobs to update. */
|
|
296
|
+
where?: JobFilter;
|
|
297
|
+
/** Fields to update on the matching jobs. */
|
|
298
|
+
apply: UpdateJobOptions;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Filter for selecting jobs in bulk operations.
|
|
302
|
+
*
|
|
303
|
+
* Used by `deleteAllJobs` and `updateAllJobs` to scope which jobs are
|
|
304
|
+
* affected. An empty filter selects all jobs.
|
|
305
|
+
*
|
|
306
|
+
* Multi-value fields accept either a single value or an array.
|
|
307
|
+
*/
|
|
308
|
+
export interface JobFilter {
|
|
309
|
+
/** Filter by job ID. Accepts a single value or an array. */
|
|
310
|
+
id?: string | string[];
|
|
311
|
+
/** Filter by status. Accepts a single value or an array. */
|
|
312
|
+
status?: JobStatus | JobStatus[];
|
|
313
|
+
/** Filter by queue name. Accepts a single value or an array. */
|
|
314
|
+
queue?: string | string[];
|
|
315
|
+
/** Filter by job type. Accepts a single value or an array. */
|
|
316
|
+
type?: string | string[];
|
|
317
|
+
/** jq expression to filter jobs by payload. */
|
|
318
|
+
filter?: string;
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Options for bulk-deleting jobs.
|
|
322
|
+
*
|
|
323
|
+
* An empty `where` filter deletes all jobs.
|
|
324
|
+
*
|
|
325
|
+
* @example
|
|
326
|
+
* ```ts
|
|
327
|
+
* // Delete all dead jobs in the emails queue
|
|
328
|
+
* const count = await client.deleteAllJobs({
|
|
329
|
+
* where: { queue: "emails", status: "dead" },
|
|
330
|
+
* });
|
|
331
|
+
* ```
|
|
332
|
+
*/
|
|
333
|
+
export interface DeleteAllJobsOptions {
|
|
334
|
+
/** Filter selecting which jobs to delete. */
|
|
335
|
+
where?: JobFilter;
|
|
336
|
+
}
|
|
337
|
+
/** Response shape for `GET /health`. */
|
|
338
|
+
interface HealthResponse {
|
|
339
|
+
status: string;
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* TLS configuration for connecting to the Zizq server over HTTPS.
|
|
343
|
+
*
|
|
344
|
+
* Values are PEM-encoded strings or Buffers. If loading from files,
|
|
345
|
+
* use `fs.readFileSync()`.
|
|
346
|
+
*
|
|
347
|
+
* @example
|
|
348
|
+
* ```ts
|
|
349
|
+
* import fs from "node:fs";
|
|
350
|
+
*
|
|
351
|
+
* const client = new Client({
|
|
352
|
+
* url: "https://localhost:7890",
|
|
353
|
+
* tls: {
|
|
354
|
+
* ca: fs.readFileSync("/path/to/ca.pem"),
|
|
355
|
+
* cert: fs.readFileSync("/path/to/client.pem"),
|
|
356
|
+
* key: fs.readFileSync("/path/to/client-key.pem"),
|
|
357
|
+
* },
|
|
358
|
+
* });
|
|
359
|
+
* ```
|
|
360
|
+
*/
|
|
361
|
+
export interface TlsOptions {
|
|
362
|
+
/** PEM-encoded CA certificate(s) for verifying the server. */
|
|
363
|
+
ca?: string | Buffer;
|
|
364
|
+
/** PEM-encoded client certificate for mTLS. Must be paired with `key`. */
|
|
365
|
+
cert?: string | Buffer;
|
|
366
|
+
/** PEM-encoded client private key for mTLS. Must be paired with `cert`. */
|
|
367
|
+
key?: string | Buffer;
|
|
368
|
+
}
|
|
369
|
+
/** Serialization format for client-server communication. */
|
|
370
|
+
export type Format = "json" | "msgpack";
|
|
371
|
+
/** Options for constructing a {@link Client}. */
|
|
372
|
+
export interface ClientOptions {
|
|
373
|
+
/** Base URL of the Zizq server, e.g. "http://localhost:7890". */
|
|
374
|
+
url: string;
|
|
375
|
+
/**
|
|
376
|
+
* Serialization format for request and response bodies.
|
|
377
|
+
*
|
|
378
|
+
* Default: "json".
|
|
379
|
+
*/
|
|
380
|
+
format?: Format;
|
|
381
|
+
/** TLS configuration for HTTPS connections. */
|
|
382
|
+
tls?: TlsOptions;
|
|
383
|
+
/** @internal For testing — override the HTTP dispatcher. */
|
|
384
|
+
dispatcher?: Dispatcher;
|
|
385
|
+
}
|
|
386
|
+
/** Base error class for all Zizq errors. */
|
|
387
|
+
export declare class ZizqError extends Error {
|
|
388
|
+
constructor(message: string);
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Network-level failure (connection refused, DNS, timeout, etc.).
|
|
392
|
+
*
|
|
393
|
+
* These are always transient and safe to retry.
|
|
394
|
+
*/
|
|
395
|
+
export declare class ConnectionError extends ZizqError {
|
|
396
|
+
constructor(message: string);
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* HTTP error — the server returned a non-success status code.
|
|
400
|
+
*
|
|
401
|
+
* Carries the HTTP status code and (when available) the parsed response
|
|
402
|
+
* body, which typically contains an `error` field with a human-readable
|
|
403
|
+
* message from the server.
|
|
404
|
+
*/
|
|
405
|
+
export declare class ResponseError extends ZizqError {
|
|
406
|
+
/** HTTP status code from the server. */
|
|
407
|
+
status: number;
|
|
408
|
+
/** Parsed response body, if available. */
|
|
409
|
+
body?: unknown;
|
|
410
|
+
constructor(message: string, status: number, body?: unknown);
|
|
411
|
+
}
|
|
412
|
+
/** 4xx client error — the request was invalid. Not retryable. */
|
|
413
|
+
export declare class ClientError extends ResponseError {
|
|
414
|
+
constructor(message: string, status: number, body?: unknown);
|
|
415
|
+
}
|
|
416
|
+
/** 404 specifically — job not found, etc. */
|
|
417
|
+
export declare class NotFoundError extends ClientError {
|
|
418
|
+
constructor(message: string, body?: unknown);
|
|
419
|
+
}
|
|
420
|
+
/** 5xx server error — something went wrong on the server. Retryable. */
|
|
421
|
+
export declare class ServerError extends ResponseError {
|
|
422
|
+
constructor(message: string, status: number, body?: unknown);
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Low-level HTTP client for the Zizq job queue server.
|
|
426
|
+
*
|
|
427
|
+
* Maintains a persistent connection (HTTP/2 when available) for efficient
|
|
428
|
+
* request multiplexing. All methods map directly to server API endpoints.
|
|
429
|
+
*
|
|
430
|
+
* Call {@link close} when done to wait for in-flight requests to complete and
|
|
431
|
+
* release the underlying connection.
|
|
432
|
+
*
|
|
433
|
+
* @example
|
|
434
|
+
* ```ts
|
|
435
|
+
* const client = new Client({ url: "http://localhost:7890" });
|
|
436
|
+
*
|
|
437
|
+
* const job = await client.enqueue({
|
|
438
|
+
* type: "send_email",
|
|
439
|
+
* queue: "emails",
|
|
440
|
+
* payload: { to: "user@example.com" },
|
|
441
|
+
* });
|
|
442
|
+
*
|
|
443
|
+
* await client.close();
|
|
444
|
+
* ```
|
|
445
|
+
*/
|
|
446
|
+
export declare class Client {
|
|
447
|
+
/** Pool for request/response traffic (enqueue, ack, failure, get). */
|
|
448
|
+
private http;
|
|
449
|
+
/** Separate pool for long-lived streaming connections (take). */
|
|
450
|
+
private streamHttp;
|
|
451
|
+
/** The base URL of the Zizq server. */
|
|
452
|
+
readonly url: string;
|
|
453
|
+
/** Serialization format. */
|
|
454
|
+
private format;
|
|
455
|
+
/** Content-type for requests. */
|
|
456
|
+
private contentType;
|
|
457
|
+
/** Accept header for request/response endpoints. */
|
|
458
|
+
private accept;
|
|
459
|
+
/** Accept header for the streaming take endpoint. */
|
|
460
|
+
private streamAccept;
|
|
461
|
+
constructor(options: ClientOptions);
|
|
462
|
+
/**
|
|
463
|
+
* Enqueue a single job.
|
|
464
|
+
*
|
|
465
|
+
* @returns The created job, including its server-assigned `id` and `status`.
|
|
466
|
+
* @throws {ZizqError} If the server rejects the request (e.g. invalid queue name).
|
|
467
|
+
*
|
|
468
|
+
* @example
|
|
469
|
+
* ```ts
|
|
470
|
+
* const job = await client.enqueue({
|
|
471
|
+
* type: "send_email",
|
|
472
|
+
* queue: "emails",
|
|
473
|
+
* payload: { to: "user@example.com" },
|
|
474
|
+
* });
|
|
475
|
+
* ```
|
|
476
|
+
*/
|
|
477
|
+
enqueue(options: EnqueueOptions): Promise<Job>;
|
|
478
|
+
/**
|
|
479
|
+
* Enqueue multiple jobs in a single request.
|
|
480
|
+
*
|
|
481
|
+
* @returns An array of created jobs in the same order as the input.
|
|
482
|
+
*
|
|
483
|
+
* @example
|
|
484
|
+
* ```ts
|
|
485
|
+
* const jobs = await client.enqueueBulk([
|
|
486
|
+
* { type: "send_email", queue: "emails", payload: { to: "a@b.com" } },
|
|
487
|
+
* { type: "send_email", queue: "emails", payload: { to: "c@d.com" } },
|
|
488
|
+
* ]);
|
|
489
|
+
* ```
|
|
490
|
+
*/
|
|
491
|
+
enqueueBulk(jobs: EnqueueOptions[]): Promise<Job[]>;
|
|
492
|
+
/**
|
|
493
|
+
* Acknowledge a job as successfully completed.
|
|
494
|
+
*
|
|
495
|
+
* @param id - The job ID to acknowledge.
|
|
496
|
+
* @throws {ZizqError} If the job is not found or not in-flight.
|
|
497
|
+
*/
|
|
498
|
+
reportSuccess(id: string): Promise<void>;
|
|
499
|
+
/**
|
|
500
|
+
* Acknowledge multiple jobs as successfully completed in a single request.
|
|
501
|
+
*
|
|
502
|
+
* Jobs that have already been acknowledged or that don't exist are
|
|
503
|
+
* silently ignored (the server returns 422 but the client treats it
|
|
504
|
+
* as success).
|
|
505
|
+
*
|
|
506
|
+
* @param ids - Array of job IDs to acknowledge.
|
|
507
|
+
*/
|
|
508
|
+
reportSuccessBulk(ids: string[]): Promise<void>;
|
|
509
|
+
/**
|
|
510
|
+
* Report a job as failed.
|
|
511
|
+
*
|
|
512
|
+
* The server will either reschedule the job with backoff or move it to
|
|
513
|
+
* the dead list if the retry limit has been exceeded.
|
|
514
|
+
*
|
|
515
|
+
* @param id - The job ID to report failure for.
|
|
516
|
+
* @param options - Error details (message, stack trace, etc.).
|
|
517
|
+
* @returns The updated job with its new status and attempt count.
|
|
518
|
+
*/
|
|
519
|
+
reportFailure(id: string, options: FailureOptions): Promise<Job>;
|
|
520
|
+
/**
|
|
521
|
+
* Fetch a single job by ID.
|
|
522
|
+
*
|
|
523
|
+
* @param id - The job ID to fetch.
|
|
524
|
+
* @returns The full job data including payload.
|
|
525
|
+
* @throws {ZizqError} If the job is not found (404).
|
|
526
|
+
*/
|
|
527
|
+
getJob(id: string): Promise<Job>;
|
|
528
|
+
/**
|
|
529
|
+
* Delete a single job by ID.
|
|
530
|
+
*
|
|
531
|
+
* @param id - The job ID to delete.
|
|
532
|
+
* @throws {NotFoundError} If the job is not found.
|
|
533
|
+
*/
|
|
534
|
+
deleteJob(id: string): Promise<void>;
|
|
535
|
+
/**
|
|
536
|
+
* Delete jobs matching the given filters.
|
|
537
|
+
*
|
|
538
|
+
* An empty options object deletes all jobs.
|
|
539
|
+
*
|
|
540
|
+
* @returns The number of deleted jobs.
|
|
541
|
+
*
|
|
542
|
+
* @example
|
|
543
|
+
* ```ts
|
|
544
|
+
* const count = await client.deleteAllJobs({ queue: "emails", status: "dead" });
|
|
545
|
+
* ```
|
|
546
|
+
*/
|
|
547
|
+
deleteAllJobs(options?: DeleteAllJobsOptions): Promise<number>;
|
|
548
|
+
/**
|
|
549
|
+
* Update a single job's mutable fields.
|
|
550
|
+
*
|
|
551
|
+
* Field semantics:
|
|
552
|
+
* - **omitted or `undefined`** — leave unchanged
|
|
553
|
+
* - **`null`** — clear the field (only valid for nullable fields)
|
|
554
|
+
* - **a value** — update to that value
|
|
555
|
+
*
|
|
556
|
+
* @param id - The job ID to update.
|
|
557
|
+
* @param options - Fields to update.
|
|
558
|
+
* @returns The updated job.
|
|
559
|
+
* @throws {NotFoundError} If the job is not found.
|
|
560
|
+
*
|
|
561
|
+
* @example
|
|
562
|
+
* ```ts
|
|
563
|
+
* // Change priority and clear the retry limit
|
|
564
|
+
* await client.updateJob("job-id", {
|
|
565
|
+
* priority: 100,
|
|
566
|
+
* retryLimit: null,
|
|
567
|
+
* });
|
|
568
|
+
* ```
|
|
569
|
+
*/
|
|
570
|
+
updateJob(id: string, options: UpdateJobOptions): Promise<Job>;
|
|
571
|
+
/**
|
|
572
|
+
* Bulk update jobs matching a filter.
|
|
573
|
+
*
|
|
574
|
+
* @returns The number of updated jobs.
|
|
575
|
+
*
|
|
576
|
+
* @example
|
|
577
|
+
* ```ts
|
|
578
|
+
* const count = await client.updateAllJobs({
|
|
579
|
+
* where: { queue: "emails", status: "ready" },
|
|
580
|
+
* apply: { priority: 1000 },
|
|
581
|
+
* });
|
|
582
|
+
* ```
|
|
583
|
+
*/
|
|
584
|
+
updateAllJobs(options: UpdateAllJobsOptions): Promise<number>;
|
|
585
|
+
/**
|
|
586
|
+
* List jobs with cursor-based pagination.
|
|
587
|
+
*
|
|
588
|
+
* Returns a single page of jobs. Use `page.nextPage()` and
|
|
589
|
+
* `page.prevPage()` to navigate between pages.
|
|
590
|
+
*
|
|
591
|
+
* @example
|
|
592
|
+
* ```ts
|
|
593
|
+
* const page = await client.listJobs({ queue: ["emails"], limit: 10 });
|
|
594
|
+
* for (const job of page.jobs) {
|
|
595
|
+
* console.log(job.id, job.status);
|
|
596
|
+
* }
|
|
597
|
+
* if (page.hasNext) {
|
|
598
|
+
* const next = await page.nextPage();
|
|
599
|
+
* }
|
|
600
|
+
* ```
|
|
601
|
+
*/
|
|
602
|
+
listJobs(options?: ListJobsOptions): Promise<JobPage>;
|
|
603
|
+
/**
|
|
604
|
+
* Fetch a page of jobs by a raw path (used internally for pagination links).
|
|
605
|
+
*
|
|
606
|
+
* @internal
|
|
607
|
+
*/
|
|
608
|
+
listJobsByPath(path: string): Promise<JobPage>;
|
|
609
|
+
/**
|
|
610
|
+
* Health check.
|
|
611
|
+
*
|
|
612
|
+
* @returns The parsed response body, e.g. `{ status: "ok" }`.
|
|
613
|
+
*/
|
|
614
|
+
health(): Promise<HealthResponse>;
|
|
615
|
+
/**
|
|
616
|
+
* Server version.
|
|
617
|
+
*
|
|
618
|
+
* @returns The server's version string.
|
|
619
|
+
*/
|
|
620
|
+
serverVersion(): Promise<string>;
|
|
621
|
+
/**
|
|
622
|
+
* Start a composable, lazy query over jobs.
|
|
623
|
+
*
|
|
624
|
+
* Returns a {@link JobQuery} that can be chained with filter and
|
|
625
|
+
* ordering methods, then iterated or used with terminal methods like
|
|
626
|
+
* `first()`, `toArray()`, `updateAll()`, and `deleteAll()`.
|
|
627
|
+
*
|
|
628
|
+
* No HTTP request is made until the query is consumed.
|
|
629
|
+
*
|
|
630
|
+
* Accepts an optional {@link JobQueryOptions} to seed the query's initial
|
|
631
|
+
* filter, order, limit, and page size — handy as a shorthand for
|
|
632
|
+
* `client.jobs().byQueue(...).limit(...)` etc.
|
|
633
|
+
*
|
|
634
|
+
* @example
|
|
635
|
+
* ```ts
|
|
636
|
+
* const dead = await client.jobs()
|
|
637
|
+
* .byQueue("emails")
|
|
638
|
+
* .byStatus("dead")
|
|
639
|
+
* .toArray();
|
|
640
|
+
*
|
|
641
|
+
* // Shorthand with seeded options
|
|
642
|
+
* const ready = await client.jobs({ queue: "emails", status: "ready" }).toArray();
|
|
643
|
+
*
|
|
644
|
+
* for await (const job of client.jobs().byStatus("ready")) {
|
|
645
|
+
* console.log(job.id);
|
|
646
|
+
* }
|
|
647
|
+
* ```
|
|
648
|
+
*/
|
|
649
|
+
jobs(options?: JobQueryOptions): JobQuery;
|
|
650
|
+
/**
|
|
651
|
+
* List all distinct queue names on the server.
|
|
652
|
+
*
|
|
653
|
+
* @returns An array of queue name strings, sorted alphabetically.
|
|
654
|
+
*/
|
|
655
|
+
queues(): Promise<string[]>;
|
|
656
|
+
/**
|
|
657
|
+
* List error records for a job with cursor-based pagination.
|
|
658
|
+
*
|
|
659
|
+
* @param id - The job ID to list errors for.
|
|
660
|
+
* @param options - Pagination and ordering options.
|
|
661
|
+
*
|
|
662
|
+
* @example
|
|
663
|
+
* ```ts
|
|
664
|
+
* const page = await client.listErrors("job-id", { order: "desc" });
|
|
665
|
+
* for (const error of page) {
|
|
666
|
+
* console.log(`Attempt ${error.attempt}: ${error.message}`);
|
|
667
|
+
* }
|
|
668
|
+
* ```
|
|
669
|
+
*/
|
|
670
|
+
listErrors(id: string, options?: ListErrorsOptions): Promise<ErrorPage>;
|
|
671
|
+
/**
|
|
672
|
+
* Fetch a page of errors by a raw path (used internally for pagination links).
|
|
673
|
+
*
|
|
674
|
+
* @internal
|
|
675
|
+
*/
|
|
676
|
+
listErrorsByPath(path: string): Promise<ErrorPage>;
|
|
677
|
+
/**
|
|
678
|
+
* Fetch a single error record for a job by attempt number.
|
|
679
|
+
*
|
|
680
|
+
* @param id - The job ID.
|
|
681
|
+
* @param attempt - The attempt number (1-based).
|
|
682
|
+
* @returns The error record for that attempt.
|
|
683
|
+
* @throws {NotFoundError} If the job or attempt is not found.
|
|
684
|
+
*/
|
|
685
|
+
getError(id: string, attempt: number): Promise<ErrorRecord>;
|
|
686
|
+
/**
|
|
687
|
+
* Connect to the streaming take endpoint and return an async generator
|
|
688
|
+
* of jobs.
|
|
689
|
+
*
|
|
690
|
+
* The returned promise resolves once the HTTP connection is established.
|
|
691
|
+
* The async generator then yields jobs as they arrive. Heartbeats in
|
|
692
|
+
* the stream are silently skipped.
|
|
693
|
+
*
|
|
694
|
+
* The generator completes when the server closes the connection. The
|
|
695
|
+
* caller may also break out of the loop explicitly to end the stream,
|
|
696
|
+
* or provide an AbortSignal to explicitly signal cancellation.
|
|
697
|
+
*
|
|
698
|
+
* @example
|
|
699
|
+
* ```ts
|
|
700
|
+
* for await (const job of await client.take({ prefetch: 5, queues: ["emails"] })) {
|
|
701
|
+
* await processJob(job.payload);
|
|
702
|
+
* await client.reportSuccess(job.id);
|
|
703
|
+
* }
|
|
704
|
+
* ```
|
|
705
|
+
*/
|
|
706
|
+
take(options?: TakeOptions): Promise<AsyncGenerator<Job>>;
|
|
707
|
+
/** Parse an NDJSON stream, yielding jobs. Empty lines are heartbeats. */
|
|
708
|
+
private iterateNdjson;
|
|
709
|
+
/**
|
|
710
|
+
* Parse a length-prefixed MessagePack stream, yielding jobs.
|
|
711
|
+
*
|
|
712
|
+
* Frame format: [4-byte big-endian length][MessagePack payload].
|
|
713
|
+
* A zero-length frame is a heartbeat and is silently skipped.
|
|
714
|
+
*/
|
|
715
|
+
private iterateMsgpackStream;
|
|
716
|
+
/** Wrap raw API data as a Job instance. */
|
|
717
|
+
private wrapJob;
|
|
718
|
+
/** Wrap raw API data as an ErrorRecord instance. */
|
|
719
|
+
private wrapError;
|
|
720
|
+
/**
|
|
721
|
+
* Gracefully close the underlying HTTP connection.
|
|
722
|
+
*
|
|
723
|
+
* Waits for in-flight requests to complete. If a streaming `take()`
|
|
724
|
+
* connection is open, this will block until it ends — use
|
|
725
|
+
* {@link destroy} for hard immediate shutdown.
|
|
726
|
+
*/
|
|
727
|
+
close(): Promise<void>;
|
|
728
|
+
/**
|
|
729
|
+
* Forcefully destroy the underlying HTTP connection.
|
|
730
|
+
*
|
|
731
|
+
* Immediately terminates all in-flight requests including any open
|
|
732
|
+
* `take()` stream. Use this when `close()` would block (e.g. after
|
|
733
|
+
* an unclean interruption in the REPL).
|
|
734
|
+
*/
|
|
735
|
+
destroy(): Promise<void>;
|
|
736
|
+
private request;
|
|
737
|
+
private post;
|
|
738
|
+
private patch;
|
|
739
|
+
private requestWithBody;
|
|
740
|
+
/** Encode a value in the configured format. */
|
|
741
|
+
private encode;
|
|
742
|
+
private handleResponse;
|
|
743
|
+
private throwOnError;
|
|
744
|
+
/** Read and decode a response body, using the content-type header to
|
|
745
|
+
* pick the correct decoder rather than assuming the requested format. */
|
|
746
|
+
private readBody;
|
|
747
|
+
}
|