@spooled/sdk 1.2.1 → 1.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 +42 -12
- package/dist/{index-CWVI9LRo.d.cts → index-BVWKEr6p.d.cts} +178 -45
- package/dist/{index-CWVI9LRo.d.ts → index-BVWKEr6p.d.ts} +178 -45
- package/dist/index.cjs +422 -184
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +49 -8
- package/dist/index.d.ts +49 -8
- package/dist/index.js +422 -185
- package/dist/index.js.map +1 -1
- package/dist/worker/index.cjs +164 -45
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.d.cts +1 -1
- package/dist/worker/index.d.ts +1 -1
- package/dist/worker/index.js +164 -45
- package/dist/worker/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -136,6 +136,20 @@ await worker.start();
|
|
|
136
136
|
process.on("SIGTERM", () => worker.stop());
|
|
137
137
|
```
|
|
138
138
|
|
|
139
|
+
`stop()` drains. The worker stops claiming, then lets running handlers finish for up to
|
|
140
|
+
`shutdownTimeout` (default 30 s). A handler that returns is completed and one that throws is
|
|
141
|
+
failed, even though the stop was requested meanwhile; `ctx.signal` is not aborted during that
|
|
142
|
+
grace period. Handlers still running when it ends are aborted and failed with "Worker shutdown
|
|
143
|
+
timeout". The worker deregisters last.
|
|
144
|
+
|
|
145
|
+
If a job has `timeoutSeconds`, the worker aborts the handler (`ctx.signal`) when it runs longer,
|
|
146
|
+
emits `job:timeout`, and fails the job with "Job timeout exceeded". The error text sent with a
|
|
147
|
+
failure is always made acceptable to the API: empty becomes "Job failed", and text over 2048
|
|
148
|
+
characters is truncated.
|
|
149
|
+
|
|
150
|
+
`complete`, `fail` and both heartbeats are retried on network errors, timeouts and 5xx, because
|
|
151
|
+
the server makes them idempotent. If an ack still fails after the retries the worker emits `error`.
|
|
152
|
+
|
|
139
153
|
Give any worker that restarts a stable `workerId` (1-128 chars, `[A-Za-z0-9._-]`). Registration then
|
|
140
154
|
upserts a single row instead of minting a new UUID each start, which otherwise leaves the previous
|
|
141
155
|
registration counting against your plan's worker limit until the stale-worker reaper clears it
|
|
@@ -203,9 +217,9 @@ Manage your organization and track usage:
|
|
|
203
217
|
// Get current usage and limits
|
|
204
218
|
const usage = await client.organizations.getUsage();
|
|
205
219
|
console.log(
|
|
206
|
-
`Active jobs: ${usage.
|
|
220
|
+
`Active jobs: ${usage.usage.activeJobs.current}/${usage.usage.activeJobs.limit}`,
|
|
207
221
|
);
|
|
208
|
-
console.log(`Plan: ${usage.plan
|
|
222
|
+
console.log(`Plan: ${usage.plan}`); // e.g. "free"
|
|
209
223
|
|
|
210
224
|
// Generate a unique slug for a new organization
|
|
211
225
|
const { slug } = await client.organizations.generateSlug("My Company");
|
|
@@ -377,6 +391,9 @@ try {
|
|
|
377
391
|
|
|
378
392
|
(Per-second rate limiting also returns `429`, as a `RateLimitError` with the default `RATE_LIMIT_EXCEEDED` code.)
|
|
379
393
|
|
|
394
|
+
A plan quota does not clear for hours, so `error.isQuota` is `true` for it and the SDK never retries it and
|
|
395
|
+
never counts it toward the circuit breaker (rate-limit 429s are retried after `Retry-After`).
|
|
396
|
+
|
|
380
397
|
## Error Handling
|
|
381
398
|
|
|
382
399
|
All errors extend `SpooledError` with specific subclasses:
|
|
@@ -398,8 +415,9 @@ try {
|
|
|
398
415
|
} else if (error instanceof AuthorizationError) {
|
|
399
416
|
console.log(`Forbidden: ${error.message}`);
|
|
400
417
|
} else if (error instanceof RateLimitError) {
|
|
401
|
-
// 429: either a plan quota (code "QUOTA_EXCEEDED") or per-second rate limiting
|
|
402
|
-
|
|
418
|
+
// 429: either a plan quota (error.isQuota, code "QUOTA_EXCEEDED") or per-second rate limiting
|
|
419
|
+
if (!error.isQuota)
|
|
420
|
+
console.log(`Retry after ${error.getRetryAfter()} seconds`);
|
|
403
421
|
} else if (isSpooledError(error)) {
|
|
404
422
|
console.log(`API error: ${error.code} - ${error.message}`);
|
|
405
423
|
}
|
|
@@ -444,15 +462,27 @@ const { jobs } = await grpcClient.queue.dequeue({
|
|
|
444
462
|
leaseDurationSecs: 300,
|
|
445
463
|
});
|
|
446
464
|
|
|
447
|
-
// Process and
|
|
465
|
+
// Process and settle. leaseId is required: the server rejects a complete/fail/renew
|
|
466
|
+
// without the lease token that dequeue returned. fail() retries by default (until the
|
|
467
|
+
// job's maxRetries run out); pass retry: false to dead-letter on purpose.
|
|
448
468
|
for (const job of jobs) {
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
469
|
+
const leaseId = job.leaseId as string;
|
|
470
|
+
try {
|
|
471
|
+
await processJob(job);
|
|
472
|
+
await grpcClient.queue.complete({
|
|
473
|
+
jobId: job.id,
|
|
474
|
+
workerId,
|
|
475
|
+
leaseId,
|
|
476
|
+
result: { success: true },
|
|
477
|
+
});
|
|
478
|
+
} catch (error) {
|
|
479
|
+
await grpcClient.queue.fail({
|
|
480
|
+
jobId: job.id,
|
|
481
|
+
workerId,
|
|
482
|
+
leaseId,
|
|
483
|
+
error: error instanceof Error ? error.message : String(error),
|
|
484
|
+
});
|
|
485
|
+
}
|
|
456
486
|
}
|
|
457
487
|
```
|
|
458
488
|
|
|
@@ -107,11 +107,11 @@ declare const DEFAULT_CONFIG: {
|
|
|
107
107
|
successThreshold: number;
|
|
108
108
|
timeout: number;
|
|
109
109
|
};
|
|
110
|
-
readonly userAgent: "@spooled/sdk-nodejs/1.
|
|
110
|
+
readonly userAgent: "@spooled/sdk-nodejs/1.3.0";
|
|
111
111
|
readonly autoRefreshToken: true;
|
|
112
112
|
};
|
|
113
113
|
/** SDK version */
|
|
114
|
-
declare const SDK_VERSION = "1.
|
|
114
|
+
declare const SDK_VERSION = "1.3.0";
|
|
115
115
|
/** API version prefix */
|
|
116
116
|
declare const API_VERSION = "v1";
|
|
117
117
|
/**
|
|
@@ -262,6 +262,20 @@ interface HttpRequestOptions {
|
|
|
262
262
|
skipResponseConversion?: boolean;
|
|
263
263
|
/** Whether to skip retry logic */
|
|
264
264
|
skipRetry?: boolean;
|
|
265
|
+
/**
|
|
266
|
+
* The request is safe to replay even though it is a POST/PATCH, so network
|
|
267
|
+
* errors, timeouts, 5xx and 408 are retried like they are for a GET.
|
|
268
|
+
*
|
|
269
|
+
* Use it only for calls the server makes idempotent: lease-fenced job and
|
|
270
|
+
* worker acks (complete/fail/heartbeat answer a replay with 409) and job
|
|
271
|
+
* creation with an idempotency key (the server returns the existing job).
|
|
272
|
+
*/
|
|
273
|
+
idempotent?: boolean;
|
|
274
|
+
/**
|
|
275
|
+
* Never try to refresh the access token when this request gets a 401.
|
|
276
|
+
* Set on the auth calls that the refresh itself makes.
|
|
277
|
+
*/
|
|
278
|
+
skipAuthRefresh?: boolean;
|
|
265
279
|
/** Optional abort signal */
|
|
266
280
|
signal?: AbortSignal;
|
|
267
281
|
}
|
|
@@ -287,8 +301,12 @@ declare class HttpClient {
|
|
|
287
301
|
private authToken;
|
|
288
302
|
/** Optional function to mint a fresh access token (set when auto-refresh is enabled) */
|
|
289
303
|
private refreshTokenFn;
|
|
290
|
-
/**
|
|
291
|
-
|
|
304
|
+
/**
|
|
305
|
+
* The refresh currently in flight, shared by every request that gets a 401
|
|
306
|
+
* meanwhile. A boolean guard here made the second concurrent 401 skip the
|
|
307
|
+
* refresh and fail even though the token was about to be replaced.
|
|
308
|
+
*/
|
|
309
|
+
private refreshInFlight;
|
|
292
310
|
constructor(config: ResolvedConfig, circuitBreaker: CircuitBreaker);
|
|
293
311
|
/**
|
|
294
312
|
* Set the authentication token
|
|
@@ -301,6 +319,13 @@ declare class HttpClient {
|
|
|
301
319
|
* refresh + retry of the original request with the new token.
|
|
302
320
|
*/
|
|
303
321
|
setRefreshTokenFn(fn: () => Promise<string>): void;
|
|
322
|
+
/**
|
|
323
|
+
* Refresh the access token once for all callers.
|
|
324
|
+
*
|
|
325
|
+
* Resolves true when a new token is installed, false when the refresh failed
|
|
326
|
+
* (the caller then surfaces its original 401).
|
|
327
|
+
*/
|
|
328
|
+
private refreshAuthToken;
|
|
304
329
|
/**
|
|
305
330
|
* Build full URL with query parameters
|
|
306
331
|
*/
|
|
@@ -329,12 +354,13 @@ declare class HttpClient {
|
|
|
329
354
|
/**
|
|
330
355
|
* Resolve the retry configuration for a request.
|
|
331
356
|
*
|
|
332
|
-
* Idempotent methods (GET/PUT/DELETE)
|
|
333
|
-
*
|
|
334
|
-
*
|
|
357
|
+
* Idempotent methods (GET/PUT/DELETE), any request carrying an idempotency
|
|
358
|
+
* key and any request marked `idempotent` retry normally. Non-idempotent
|
|
359
|
+
* methods (POST/PATCH) otherwise must NOT be retried on ambiguous failures
|
|
335
360
|
* (network/timeout/5xx) — doing so risks duplicate jobs, double claims,
|
|
336
|
-
* etc. They are still retried on 429, which is rejected before
|
|
337
|
-
* server processes the request and is therefore side-effect-free.
|
|
361
|
+
* etc. They are still retried on a rate-limit 429, which is rejected before
|
|
362
|
+
* the server processes the request and is therefore side-effect-free. A
|
|
363
|
+
* quota 429 is never retried: it does not clear for hours.
|
|
338
364
|
*/
|
|
339
365
|
private resolveRetryConfig;
|
|
340
366
|
/**
|
|
@@ -624,6 +650,8 @@ interface CreateJobParams {
|
|
|
624
650
|
parentJobId?: string;
|
|
625
651
|
/** Webhook URL for completion notification */
|
|
626
652
|
completionWebhook?: string;
|
|
653
|
+
/** HMAC secret used to sign the `completionWebhook` request (never returned by the API) */
|
|
654
|
+
completionWebhookSecret?: string;
|
|
627
655
|
}
|
|
628
656
|
/** Result of creating a job */
|
|
629
657
|
interface CreateJobResult {
|
|
@@ -858,12 +886,20 @@ declare class JobsResource {
|
|
|
858
886
|
claim(params: ClaimJobsParams): Promise<ClaimJobsResult>;
|
|
859
887
|
/**
|
|
860
888
|
* Complete a job (worker ack)
|
|
889
|
+
*
|
|
890
|
+
* Lease-fenced and idempotent on the server, so a network error, timeout or
|
|
891
|
+
* 5xx is retried: a lost ack would otherwise re-run a finished job.
|
|
861
892
|
*/
|
|
862
893
|
complete(id: string, params: CompleteJobParams): Promise<{
|
|
863
894
|
success: boolean;
|
|
864
895
|
}>;
|
|
865
896
|
/**
|
|
866
897
|
* Fail a job (worker nack)
|
|
898
|
+
*
|
|
899
|
+
* `params.error` is made acceptable first: empty text becomes "Job failed"
|
|
900
|
+
* and text over 2048 characters is truncated, because the API rejects both
|
|
901
|
+
* with a 400 that would leave the job processing until its lease expires.
|
|
902
|
+
* Retried like {@link JobsResource.complete}.
|
|
867
903
|
*/
|
|
868
904
|
fail(id: string, params: FailJobParams): Promise<{
|
|
869
905
|
success: boolean;
|
|
@@ -871,6 +907,9 @@ declare class JobsResource {
|
|
|
871
907
|
}>;
|
|
872
908
|
/**
|
|
873
909
|
* Extend job lease (heartbeat)
|
|
910
|
+
*
|
|
911
|
+
* Retried like {@link JobsResource.complete}: with the default 30 s lease and
|
|
912
|
+
* 15 s heartbeat, one lost heartbeat leaves no slack.
|
|
874
913
|
*/
|
|
875
914
|
heartbeat(id: string, params: HeartbeatJobParams): Promise<{
|
|
876
915
|
success: boolean;
|
|
@@ -946,6 +985,14 @@ interface ResumeQueueResponse {
|
|
|
946
985
|
resumed: boolean;
|
|
947
986
|
pausedDurationSecs: number;
|
|
948
987
|
}
|
|
988
|
+
/** Options for deleting a queue */
|
|
989
|
+
interface DeleteQueueOptions {
|
|
990
|
+
/**
|
|
991
|
+
* Also delete every job (and dead-letter row) of the queue. Required to
|
|
992
|
+
* delete a queue with pending/processing jobs or one without a stored config.
|
|
993
|
+
*/
|
|
994
|
+
deleteJobs?: boolean;
|
|
995
|
+
}
|
|
949
996
|
|
|
950
997
|
/**
|
|
951
998
|
* Queues Resource
|
|
@@ -982,8 +1029,14 @@ declare class QueuesResource {
|
|
|
982
1029
|
resume(name: string): Promise<ResumeQueueResponse>;
|
|
983
1030
|
/**
|
|
984
1031
|
* Delete a queue configuration
|
|
1032
|
+
*
|
|
1033
|
+
* Without `deleteJobs` the API only deletes an explicit queue config of an
|
|
1034
|
+
* idle queue, and answers 409 otherwise: a queue that exists only because
|
|
1035
|
+
* jobs were posted to it has no config to delete, and a queue with pending
|
|
1036
|
+
* or processing jobs is not idle. Pass `{ deleteJobs: true }` to delete the
|
|
1037
|
+
* queue's jobs (and DLQ rows) along with it.
|
|
985
1038
|
*/
|
|
986
|
-
delete(name: string): Promise<void>;
|
|
1039
|
+
delete(name: string, options?: DeleteQueueOptions): Promise<void>;
|
|
987
1040
|
}
|
|
988
1041
|
|
|
989
1042
|
/**
|
|
@@ -1090,6 +1143,8 @@ declare class WorkersResource {
|
|
|
1090
1143
|
register(params: RegisterWorkerParams): Promise<RegisterWorkerResponse>;
|
|
1091
1144
|
/**
|
|
1092
1145
|
* Send worker heartbeat
|
|
1146
|
+
*
|
|
1147
|
+
* Idempotent on the server, so network errors, timeouts and 5xx are retried.
|
|
1093
1148
|
*/
|
|
1094
1149
|
heartbeat(id: string, params: WorkerHeartbeatParams): Promise<void>;
|
|
1095
1150
|
/**
|
|
@@ -1359,8 +1414,12 @@ interface WorkflowJob {
|
|
|
1359
1414
|
id: string;
|
|
1360
1415
|
/** Workflow ID this job belongs to */
|
|
1361
1416
|
workflowId: string;
|
|
1362
|
-
/**
|
|
1363
|
-
|
|
1417
|
+
/**
|
|
1418
|
+
* Job key within the workflow. The API does not return it (a job stores only
|
|
1419
|
+
* its workflow step), so this is undefined today; take the key to job ID
|
|
1420
|
+
* mapping from the `jobIds` of `workflows.create()`.
|
|
1421
|
+
*/
|
|
1422
|
+
key?: string;
|
|
1364
1423
|
/** Queue name */
|
|
1365
1424
|
queueName: string;
|
|
1366
1425
|
/** Current job status */
|
|
@@ -1392,8 +1451,8 @@ interface WorkflowJob {
|
|
|
1392
1451
|
interface WorkflowJobStatus {
|
|
1393
1452
|
/** Job ID */
|
|
1394
1453
|
jobId: string;
|
|
1395
|
-
/** Job key within the workflow */
|
|
1396
|
-
key
|
|
1454
|
+
/** Job key within the workflow; undefined, see {@link WorkflowJob.key} */
|
|
1455
|
+
key?: string;
|
|
1397
1456
|
/** Current status */
|
|
1398
1457
|
status: string;
|
|
1399
1458
|
/** Progress percentage (0-100) */
|
|
@@ -1415,7 +1474,7 @@ interface WorkflowJobOperations {
|
|
|
1415
1474
|
* @example
|
|
1416
1475
|
* ```typescript
|
|
1417
1476
|
* const jobs = await client.workflows.jobs.list('wf_123');
|
|
1418
|
-
* console.log('Jobs:', jobs.map(j => j.
|
|
1477
|
+
* console.log('Jobs:', jobs.map(j => j.id));
|
|
1419
1478
|
* ```
|
|
1420
1479
|
*/
|
|
1421
1480
|
list(workflowId: string): Promise<WorkflowJob[]>;
|
|
@@ -1434,14 +1493,16 @@ interface WorkflowJobOperations {
|
|
|
1434
1493
|
/**
|
|
1435
1494
|
* Get the status of all jobs in a workflow.
|
|
1436
1495
|
*
|
|
1437
|
-
* Returns a summary of each job's status
|
|
1496
|
+
* Returns a summary of each job's status. The API does not store or return
|
|
1497
|
+
* the `key` a job was created with, so `key` is undefined; map keys to job
|
|
1498
|
+
* IDs from the `jobIds` array that `workflows.create()` returns.
|
|
1438
1499
|
*
|
|
1439
1500
|
* @param workflowId - The workflow ID
|
|
1440
1501
|
* @example
|
|
1441
1502
|
* ```typescript
|
|
1442
1503
|
* const statuses = await client.workflows.jobs.getStatus('wf_123');
|
|
1443
1504
|
* for (const s of statuses) {
|
|
1444
|
-
* console.log(`${s.
|
|
1505
|
+
* console.log(`${s.jobId}: ${s.status}`);
|
|
1445
1506
|
* }
|
|
1446
1507
|
* ```
|
|
1447
1508
|
*/
|
|
@@ -1951,14 +2012,12 @@ declare class OrganizationsResource {
|
|
|
1951
2012
|
/**
|
|
1952
2013
|
* Clear/delete the webhook token for the current organization.
|
|
1953
2014
|
*
|
|
1954
|
-
*
|
|
1955
|
-
*
|
|
1956
|
-
*
|
|
1957
|
-
*
|
|
1958
|
-
* @
|
|
1959
|
-
*
|
|
1960
|
-
* await client.organizations.clearWebhookToken();
|
|
1961
|
-
* ```
|
|
2015
|
+
* @deprecated The API refuses this operation on purpose (an org without a
|
|
2016
|
+
* webhook token would have an open public ingestion endpoint) and always
|
|
2017
|
+
* answers with an error. This method now throws
|
|
2018
|
+
* {@link UnsupportedOperationError} without a network call; rotate the token
|
|
2019
|
+
* with {@link OrganizationsResource.regenerateWebhookToken} instead. It will
|
|
2020
|
+
* be removed in the next major release.
|
|
1962
2021
|
*/
|
|
1963
2022
|
clearWebhookToken(): Promise<void>;
|
|
1964
2023
|
}
|
|
@@ -2271,8 +2330,9 @@ declare class AdminResource {
|
|
|
2271
2330
|
/**
|
|
2272
2331
|
* Webhook Ingestion Types
|
|
2273
2332
|
*
|
|
2274
|
-
*
|
|
2275
|
-
*
|
|
2333
|
+
* The custom endpoint is called by external webhook providers and is
|
|
2334
|
+
* authenticated by the org webhook token (not an API key). The GitHub and
|
|
2335
|
+
* Stripe option types are kept only so existing code still compiles.
|
|
2276
2336
|
*/
|
|
2277
2337
|
|
|
2278
2338
|
interface IngestCustomWebhookParams {
|
|
@@ -2288,6 +2348,7 @@ interface IngestCustomWebhookResponse {
|
|
|
2288
2348
|
queueName?: string;
|
|
2289
2349
|
status?: string;
|
|
2290
2350
|
}
|
|
2351
|
+
/** @deprecated The API has no GitHub webhook route; `ingest.github` throws. */
|
|
2291
2352
|
interface IngestGitHubWebhookOptions {
|
|
2292
2353
|
/** Value for X-GitHub-Event header (e.g. "pull_request") */
|
|
2293
2354
|
githubEvent: string;
|
|
@@ -2300,6 +2361,7 @@ interface IngestGitHubWebhookOptions {
|
|
|
2300
2361
|
/** If provided, the SDK will compute the signature for you */
|
|
2301
2362
|
secret?: string;
|
|
2302
2363
|
}
|
|
2364
|
+
/** @deprecated The API has no Stripe webhook route; `ingest.stripe` throws. */
|
|
2303
2365
|
interface IngestStripeWebhookOptions {
|
|
2304
2366
|
/** Optional org-scoped webhook token (X-Webhook-Token) */
|
|
2305
2367
|
webhookToken?: string;
|
|
@@ -2316,8 +2378,9 @@ interface IngestStripeWebhookOptions {
|
|
|
2316
2378
|
/**
|
|
2317
2379
|
* Webhook Ingestion Resource
|
|
2318
2380
|
*
|
|
2319
|
-
*
|
|
2320
|
-
*
|
|
2381
|
+
* The Spooled API ingests webhooks on one route:
|
|
2382
|
+
* `POST /api/v1/webhooks/{org_id}/custom`, authenticated by the org's webhook
|
|
2383
|
+
* token. The GitHub and Stripe routes were removed from the API.
|
|
2321
2384
|
*/
|
|
2322
2385
|
|
|
2323
2386
|
declare class WebhookIngestionResource {
|
|
@@ -2326,15 +2389,23 @@ declare class WebhookIngestionResource {
|
|
|
2326
2389
|
/**
|
|
2327
2390
|
* Ingest a GitHub webhook.
|
|
2328
2391
|
*
|
|
2329
|
-
*
|
|
2392
|
+
* @deprecated The API has no `/webhooks/{org_id}/github` route (it always
|
|
2393
|
+
* answered 404). This method now throws {@link UnsupportedOperationError}
|
|
2394
|
+
* without a network call; point the GitHub webhook at `ingest.custom` /
|
|
2395
|
+
* `POST /api/v1/webhooks/{org_id}/custom` instead. It will be removed in the
|
|
2396
|
+
* next major release.
|
|
2330
2397
|
*/
|
|
2331
|
-
github(
|
|
2398
|
+
github(_orgId: string, _body: string | Uint8Array | ArrayBuffer, _options: IngestGitHubWebhookOptions): Promise<void>;
|
|
2332
2399
|
/**
|
|
2333
2400
|
* Ingest a Stripe webhook.
|
|
2334
2401
|
*
|
|
2335
|
-
*
|
|
2402
|
+
* @deprecated The API has no `/webhooks/{org_id}/stripe` route (it always
|
|
2403
|
+
* answered 404). This method now throws {@link UnsupportedOperationError}
|
|
2404
|
+
* without a network call; point the Stripe webhook at `ingest.custom` /
|
|
2405
|
+
* `POST /api/v1/webhooks/{org_id}/custom` instead. It will be removed in the
|
|
2406
|
+
* next major release.
|
|
2336
2407
|
*/
|
|
2337
|
-
stripe(
|
|
2408
|
+
stripe(_orgId: string, _body: string | Uint8Array | ArrayBuffer, _options?: IngestStripeWebhookOptions): Promise<void>;
|
|
2338
2409
|
/**
|
|
2339
2410
|
* Ingest a custom webhook.
|
|
2340
2411
|
*
|
|
@@ -2758,8 +2829,11 @@ interface GrpcCompleteRequest {
|
|
|
2758
2829
|
workerId: string;
|
|
2759
2830
|
/** Result as object (will be converted to google.protobuf.Struct) */
|
|
2760
2831
|
result?: Record<string, unknown>;
|
|
2761
|
-
/**
|
|
2762
|
-
|
|
2832
|
+
/**
|
|
2833
|
+
* Lease fencing token from the dequeued job (proto `lease_id`). Required: the
|
|
2834
|
+
* server rejects a settlement without it with INVALID_ARGUMENT.
|
|
2835
|
+
*/
|
|
2836
|
+
leaseId: string;
|
|
2763
2837
|
}
|
|
2764
2838
|
/** Complete response */
|
|
2765
2839
|
interface GrpcCompleteResponse {
|
|
@@ -2770,9 +2844,18 @@ interface GrpcFailRequest {
|
|
|
2770
2844
|
jobId: string;
|
|
2771
2845
|
workerId: string;
|
|
2772
2846
|
error: string;
|
|
2847
|
+
/**
|
|
2848
|
+
* Retry the job (until its `maxRetries` run out) instead of dead-lettering it
|
|
2849
|
+
* at once. Defaults to `true` here; the wire default would be `false`, which
|
|
2850
|
+
* dead-letters the job on its first failure whatever `maxRetries` says. Pass
|
|
2851
|
+
* `false` explicitly to dead-letter.
|
|
2852
|
+
*/
|
|
2773
2853
|
retry?: boolean;
|
|
2774
|
-
/**
|
|
2775
|
-
|
|
2854
|
+
/**
|
|
2855
|
+
* Lease fencing token from the dequeued job (proto `lease_id`). Required: the
|
|
2856
|
+
* server rejects a settlement without it with INVALID_ARGUMENT.
|
|
2857
|
+
*/
|
|
2858
|
+
leaseId: string;
|
|
2776
2859
|
}
|
|
2777
2860
|
/** Fail response */
|
|
2778
2861
|
interface GrpcFailResponse {
|
|
@@ -2785,8 +2868,11 @@ interface GrpcRenewLeaseRequest {
|
|
|
2785
2868
|
jobId: string;
|
|
2786
2869
|
workerId: string;
|
|
2787
2870
|
extensionSecs: number;
|
|
2788
|
-
/**
|
|
2789
|
-
|
|
2871
|
+
/**
|
|
2872
|
+
* Lease fencing token from the dequeued job (proto `lease_id`). Required: the
|
|
2873
|
+
* server rejects a renewal without it with INVALID_ARGUMENT.
|
|
2874
|
+
*/
|
|
2875
|
+
leaseId: string;
|
|
2790
2876
|
}
|
|
2791
2877
|
/** Renew lease response */
|
|
2792
2878
|
interface GrpcRenewLeaseResponse {
|
|
@@ -3319,6 +3405,13 @@ declare class SpooledClient {
|
|
|
3319
3405
|
/**
|
|
3320
3406
|
* Exchange the API key for a JWT via /auth/login and cache the result.
|
|
3321
3407
|
*
|
|
3408
|
+
* The JWT belongs to the realtime transport only. It must NOT replace the
|
|
3409
|
+
* REST bearer: an API-key client has no refresh token wired into its HTTP
|
|
3410
|
+
* layer, so after the JWT's 24 h lifetime every REST call (claim, complete,
|
|
3411
|
+
* heartbeat, create) would have failed with 401 for good. REST keeps using
|
|
3412
|
+
* the API key; realtime re-mints its own JWT near expiry (see
|
|
3413
|
+
* `getJwtToken`).
|
|
3414
|
+
*
|
|
3322
3415
|
* Concurrent callers share a single in-flight login so a burst of reconnects
|
|
3323
3416
|
* (e.g. WebSocket and SSE at once) issues just one request.
|
|
3324
3417
|
*/
|
|
@@ -3416,7 +3509,10 @@ interface SpooledWorkerOptions {
|
|
|
3416
3509
|
version?: string;
|
|
3417
3510
|
/** Additional worker metadata */
|
|
3418
3511
|
metadata?: JsonObject;
|
|
3419
|
-
/**
|
|
3512
|
+
/**
|
|
3513
|
+
* Graceful shutdown timeout in ms (default: 30000): how long `stop()` lets
|
|
3514
|
+
* running handlers finish before aborting and failing them.
|
|
3515
|
+
*/
|
|
3420
3516
|
shutdownTimeout?: number;
|
|
3421
3517
|
}
|
|
3422
3518
|
/** Worker state */
|
|
@@ -3433,7 +3529,12 @@ interface JobContext {
|
|
|
3433
3529
|
retryCount: number;
|
|
3434
3530
|
/** Maximum retries */
|
|
3435
3531
|
maxRetries: number;
|
|
3436
|
-
/**
|
|
3532
|
+
/**
|
|
3533
|
+
* Abort signal. Aborted when the job exceeds its `timeoutSeconds` or when a
|
|
3534
|
+
* stop outlives `shutdownTimeout`; NOT aborted merely because a stop was
|
|
3535
|
+
* requested (the handler gets the grace period to finish and be acked).
|
|
3536
|
+
* `signal.reason` carries the cause.
|
|
3537
|
+
*/
|
|
3437
3538
|
signal: AbortSignal;
|
|
3438
3539
|
/** Log local job progress (0-100); backend progress persistence is not yet available. */
|
|
3439
3540
|
progress: (percent: number, message?: string) => Promise<void>;
|
|
@@ -3493,7 +3594,16 @@ interface ActiveJob {
|
|
|
3493
3594
|
job: ClaimedJob;
|
|
3494
3595
|
startedAt: Date;
|
|
3495
3596
|
heartbeatTimer?: ReturnType<typeof setInterval>;
|
|
3597
|
+
/** Fires when the job exceeds its `timeoutSeconds` */
|
|
3598
|
+
timeoutTimer?: ReturnType<typeof setTimeout>;
|
|
3496
3599
|
abortController: AbortController;
|
|
3600
|
+
/**
|
|
3601
|
+
* The outcome of this execution is decided (acked, or about to be): nothing
|
|
3602
|
+
* else may ack it. Set when the handler settles or the shutdown fails it.
|
|
3603
|
+
*/
|
|
3604
|
+
settled?: boolean;
|
|
3605
|
+
/** The complete/fail request for this execution, once started. */
|
|
3606
|
+
ack?: Promise<void>;
|
|
3497
3607
|
}
|
|
3498
3608
|
|
|
3499
3609
|
/**
|
|
@@ -3542,6 +3652,10 @@ declare class SpooledWorker {
|
|
|
3542
3652
|
private pollTimer;
|
|
3543
3653
|
private workerHeartbeatTimer;
|
|
3544
3654
|
private shutdownPromise;
|
|
3655
|
+
/** The claim request currently on the wire, so a stop can wait for its jobs. */
|
|
3656
|
+
private pollInFlight;
|
|
3657
|
+
/** Wakes the shutdown drain when the last active job has been acked. */
|
|
3658
|
+
private drainWaiter;
|
|
3545
3659
|
private eventHandlers;
|
|
3546
3660
|
constructor(client: SpooledClient, options: SpooledWorkerOptions);
|
|
3547
3661
|
/**
|
|
@@ -3565,7 +3679,15 @@ declare class SpooledWorker {
|
|
|
3565
3679
|
*/
|
|
3566
3680
|
start(): Promise<void>;
|
|
3567
3681
|
/**
|
|
3568
|
-
* Stop the worker gracefully
|
|
3682
|
+
* Stop the worker gracefully.
|
|
3683
|
+
*
|
|
3684
|
+
* Drains: the worker stops claiming, then lets running handlers finish for
|
|
3685
|
+
* up to `shutdownTimeout`. A handler that returns completes its job and one
|
|
3686
|
+
* that throws fails it, even though a stop was requested meanwhile; its
|
|
3687
|
+
* `signal` is NOT aborted during the grace period. Only handlers still
|
|
3688
|
+
* running when the timeout ends are aborted and failed with "Worker shutdown
|
|
3689
|
+
* timeout". The worker deregisters last, because deregistering returns every
|
|
3690
|
+
* job the worker still holds to the queue.
|
|
3569
3691
|
*/
|
|
3570
3692
|
stop(): Promise<void>;
|
|
3571
3693
|
private doStop;
|
|
@@ -3582,13 +3704,24 @@ declare class SpooledWorker {
|
|
|
3582
3704
|
private poll;
|
|
3583
3705
|
private processJob;
|
|
3584
3706
|
private executeHandler;
|
|
3707
|
+
/**
|
|
3708
|
+
* Run the handler, racing it against the job's `timeoutSeconds`.
|
|
3709
|
+
* Never rejects: a throw (sync or async) is reported as an outcome.
|
|
3710
|
+
*/
|
|
3711
|
+
private runHandler;
|
|
3712
|
+
/** Abort a handler that outlived the shutdown grace period and fail its job. */
|
|
3713
|
+
private abandonJob;
|
|
3585
3714
|
private completeJob;
|
|
3586
3715
|
private failJob;
|
|
3716
|
+
private clearTimeoutTimer;
|
|
3587
3717
|
private cleanupJob;
|
|
3588
3718
|
private sendJobHeartbeat;
|
|
3589
3719
|
private sendWorkerHeartbeat;
|
|
3590
|
-
|
|
3591
|
-
|
|
3720
|
+
/**
|
|
3721
|
+
* Resolve once no job is active, or after `timeoutMs`. The timer is always
|
|
3722
|
+
* cleared, so a clean stop leaves nothing that keeps the process alive.
|
|
3723
|
+
*/
|
|
3724
|
+
private waitForDrain;
|
|
3592
3725
|
}
|
|
3593
3726
|
|
|
3594
|
-
export { type CreateWorkflowParams as $, API_VERSION as A, type BatchJobStatus as B, type ConnectionState as C, type BulkEnqueueResponse as D, type BulkJobItem as E, type CheckEmailResponse as F, type CheckSlugResponse as G, CircuitBreaker as H, type CircuitBreakerConfig as I, CircuitState as J, type ClaimJobsParams as K, type ClaimJobsResult as L, type ClaimedJob as M, type CompleteJobParams as N, type CreateApiKeyParams as O, type CreateApiKeyResponse as P, type CreateBillingPortalParams as Q, type RealtimeConnectionOptions as R, type SubscriptionFilter as S, type CreateBillingPortalResponse as T, type CreateJobParams as U, type CreateJobResult as V, type CreateOrganizationParams as W, type CreateOrganizationResponse as X, type CreateOutgoingWebhookParams as Y, type CreateScheduleParams as Z, type CreateScheduleResponse as _, type RealtimeEventType as a, type
|
|
3727
|
+
export { type CreateWorkflowParams as $, API_VERSION as A, type BatchJobStatus as B, type ConnectionState as C, type BulkEnqueueResponse as D, type BulkJobItem as E, type CheckEmailResponse as F, type CheckSlugResponse as G, CircuitBreaker as H, type CircuitBreakerConfig as I, CircuitState as J, type ClaimJobsParams as K, type ClaimJobsResult as L, type ClaimedJob as M, type CompleteJobParams as N, type CreateApiKeyParams as O, type CreateApiKeyResponse as P, type CreateBillingPortalParams as Q, type RealtimeConnectionOptions as R, type SubscriptionFilter as S, type CreateBillingPortalResponse as T, type CreateJobParams as U, type CreateJobResult as V, type CreateOrganizationParams as W, type CreateOrganizationResponse as X, type CreateOutgoingWebhookParams as Y, type CreateScheduleParams as Z, type CreateScheduleResponse as _, type RealtimeEventType as a, type IngestCustomWebhookResponse as a$, type CreateWorkflowResponse as a0, type CurrentUserResponse as a1, DEFAULT_CONFIG as a2, type DashboardData as a3, DashboardResource as a4, type DashboardWorkerSummary as a5, type DebugFn as a6, type DeleteQueueOptions as a7, type DependencyInfo as a8, type DependencyMode as a9, type GrpcHeartbeatParams as aA, type GrpcHeartbeatRequest as aB, type GrpcHeartbeatResponse as aC, type GrpcHeartbeatResponse_Legacy as aD, type GrpcJob as aE, GrpcJobStatus as aF, GrpcJobStatusNumber as aG, type GrpcProcessRequest as aH, type GrpcProcessResponse as aI, GrpcQueueOperations as aJ, type GrpcRegisterWorkerParams as aK, type GrpcRegisterWorkerRequest as aL, type GrpcRegisterWorkerResponse as aM, type GrpcRegisterWorkerResponse_Legacy as aN, type GrpcRenewLeaseParams as aO, type GrpcRenewLeaseRequest as aP, type GrpcRenewLeaseResponse as aQ, type GrpcRenewLeaseResponse_Legacy as aR, type GrpcStreamJobsRequest as aS, type GrpcTimestamp as aT, GrpcWorkerOperations as aU, HealthResource as aV, type HealthResponse as aW, type HeartbeatEvent as aX, type HeartbeatJobParams as aY, HttpClient as aZ, type IngestCustomWebhookParams as a_, type FailJobParams as aa, type GrpcClientOptions as ab, type GrpcCompleteJobParams as ac, type GrpcCompleteJobResponse as ad, type GrpcCompleteRequest as ae, type GrpcCompleteResponse as af, type GrpcDequeueJobParams as ag, type GrpcDequeueJobResponse as ah, type GrpcDequeueRequest as ai, type GrpcDequeueResponse as aj, type GrpcDeregisterRequest as ak, type GrpcDeregisterResponse as al, type GrpcEnqueueJobParams as am, type GrpcEnqueueJobResponse as an, type GrpcEnqueueRequest as ao, type GrpcEnqueueResponse as ap, type GrpcErrorResponse as aq, type GrpcFailJobParams as ar, type GrpcFailJobResponse as as, type GrpcFailRequest as at, type GrpcFailResponse as au, type GrpcGetJobRequest as av, type GrpcGetJobResponse as aw, type GrpcGetQueueStatsRequest as ax, type GrpcGetQueueStatsResponse as ay, type GrpcGetQueueStatsResponse_Legacy as az, type RealtimeEvent as b, type ResumeQueueResponse as b$, type IngestGitHubWebhookOptions as b0, type IngestStripeWebhookOptions as b1, type InitialApiKey as b2, type Job as b3, type JobCompletedEvent as b4, type JobContext as b5, type JobCreatedEvent as b6, type JobFailedEvent as b7, type JobHandler as b8, type JobProgressEvent as b9, OrganizationsResource as bA, type OutgoingWebhook as bB, type OutgoingWebhookDelivery as bC, type PaginatedResponse as bD, type PaginationParams as bE, type PauseQueueResponse as bF, type PlanCount as bG, type PlanLimits as bH, type PlanTier as bI, type ProcessJobsStream as bJ, type PurgeDlqParams as bK, type PurgeDlqResponse as bL, type QueueConfig as bM, type QueueConfigSummary as bN, type QueuePausedEvent as bO, type QueueResumedEvent as bP, type QueueStats as bQ, type QueueSummary as bR, QueuesResource as bS, type RealtimeEventData as bT, type RecentActivity as bU, type RefreshTokenParams as bV, type RefreshTokenResponse as bW, type RegisterWorkerParams as bX, type RegisterWorkerResponse as bY, type ResolvedConfig as bZ, type ResourceUsage as b_, type JobResult as ba, type JobStartedEvent as bb, type JobStats as bc, type JobStatus as bd, type JobStatusChangedEvent as be, type JobStream as bf, type JobSummary as bg, type JobSummaryStats as bh, type JobWithDependencies as bi, JobsResource as bj, type JsonArray as bk, type JsonObject as bl, type JsonPrimitive as bm, type JsonValue as bn, type ListDlqParams as bo, type ListJobsParams as bp, type ListParams as bq, type ListSchedulesParams as br, type ListWorkflowsParams as bs, type LoginParams as bt, type LoginResponse as bu, MetricsResource as bv, type Organization as bw, type OrganizationMember as bx, type OrganizationSummary as by, type OrganizationUsage as bz, type RetryConfig as c, type ActiveJob as c$, type RetryDlqParams as c0, type RetryDlqResponse as c1, SDK_VERSION as c2, type Schedule as c3, type ScheduleRun as c4, type ScheduleRunStatus as c5, type ScheduleTriggeredEvent as c6, SchedulesResource as c7, SpooledClient as c8, type SpooledClientConfig as c9, type WorkerDeregisteredEvent as cA, type WorkerEvent as cB, type WorkerEventData as cC, type WorkerHeartbeatParams as cD, type WorkerRegisteredEvent as cE, type WorkerState as cF, type WorkerStatus as cG, type WorkerSummary as cH, WorkersResource as cI, type Workflow as cJ, type WorkflowJob as cK, type WorkflowJobDefinition as cL, type WorkflowJobStatus as cM, type WorkflowResponse as cN, type WorkflowStatus as cO, WorkflowsResource as cP, asyncIterableFromStream as cQ, createCircuitBreaker as cR, createClient as cS, createHttpClient as cT, createJobStream as cU, createPaginatedResponse as cV, createProcessJobsStream as cW, dateToTimestamp as cX, resolveConfig as cY, timestampToDate as cZ, validateConfig as c_, SpooledGrpcClient as ca, SpooledRealtime as cb, type SpooledRealtimeOptions as cc, SpooledWorker as cd, type SpooledWorkerOptions as ce, type StartEmailLoginResponse as cf, type StreamOptions as cg, type SystemInfo as ch, type TestWebhookResponse as ci, type TokenClaims as cj, type TriggerScheduleResponse as ck, type UpdateApiKeyParams as cl, type UpdateOrganizationParams as cm, type UpdateOutgoingWebhookParams as cn, type UpdateQueueConfigParams as co, type UpdateScheduleParams as cp, type UsageItem as cq, type UsageWarning as cr, type ValidateTokenParams as cs, type ValidateTokenResponse as ct, type WebhookDeliveryStatus as cu, type WebhookEventType as cv, WebhookIngestionResource as cw, type WebhookTokenResponse as cx, WebhooksResource as cy, type Worker as cz, type AddDependenciesParams as d, type AddDependenciesResponse as e, type AdminApiKeyResponse as f, type AdminCreateApiKeyParams as g, type AdminCreateOrganizationParams as h, type AdminCreateOrganizationResponse as i, type AdminDeleteOrganizationParams as j, type AdminListOrganizationsParams as k, type AdminOrganizationDetail as l, type AdminOrganizationList as m, type AdminOrganizationSummary as n, type AdminPlanLimits as o, type AdminPlatformStats as p, AdminResource as q, type AdminUpdateOrganizationParams as r, type AdminUsageStats as s, type ApiKeySummary as t, ApiKeysResource as u, AuthResource as v, BillingResource as w, type BillingStatus as x, type BoostPriorityResponse as y, type BulkEnqueueParams as z };
|