@porulle/core 0.17.0 → 0.19.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/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/interfaces/rest/router.d.ts +21 -0
- package/dist/interfaces/rest/router.d.ts.map +1 -1
- package/dist/interfaces/rest/router.js +22 -1
- package/dist/interfaces/rest/schemas/admin-jobs.d.ts +2 -2
- package/dist/interfaces/rest/schemas/responses.d.ts +4 -4
- package/dist/jobs.d.ts +5 -0
- package/dist/jobs.d.ts.map +1 -0
- package/dist/jobs.js +2 -0
- package/dist/kernel/jobs/adapter.d.ts +13 -1
- package/dist/kernel/jobs/adapter.d.ts.map +1 -1
- package/dist/kernel/jobs/drizzle-adapter.d.ts +9 -1
- package/dist/kernel/jobs/drizzle-adapter.d.ts.map +1 -1
- package/dist/kernel/jobs/drizzle-adapter.js +32 -1
- package/dist/kernel/jobs/runner.d.ts.map +1 -1
- package/dist/kernel/jobs/runner.js +6 -2
- package/dist/kernel/jobs/schema.d.ts +2 -2
- package/dist/kernel/jobs/schema.js +1 -1
- package/dist/kernel/jobs/step.d.ts +8 -0
- package/dist/kernel/jobs/step.d.ts.map +1 -0
- package/dist/kernel/jobs/step.js +24 -0
- package/dist/kernel/jobs/types.d.ts +27 -0
- package/dist/kernel/jobs/types.d.ts.map +1 -1
- package/dist/kernel/jobs/types.js +9 -0
- package/package.json +7 -1
- package/src/index.ts +4 -1
- package/src/interfaces/rest/router.ts +23 -1
- package/src/jobs.ts +18 -0
- package/src/kernel/jobs/adapter.ts +12 -0
- package/src/kernel/jobs/drizzle-adapter.ts +43 -2
- package/src/kernel/jobs/runner.ts +6 -2
- package/src/kernel/jobs/schema.ts +1 -1
- package/src/kernel/jobs/step.ts +27 -0
- package/src/kernel/jobs/types.ts +43 -0
package/dist/index.d.ts
CHANGED
|
@@ -34,8 +34,9 @@ export { NullJobsAdapter } from "./kernel/jobs/adapter.js";
|
|
|
34
34
|
export { DrizzleJobsAdapter } from "./kernel/jobs/drizzle-adapter.js";
|
|
35
35
|
export { runPendingJobs } from "./kernel/jobs/runner.js";
|
|
36
36
|
export type { RunPendingJobsArgs } from "./kernel/jobs/runner.js";
|
|
37
|
-
export type { TaskDefinition, TaskContext, TaskJobMeta, TaskRetryConfig, JobProcessingOrder, JobProcessingOrderField, JobProcessingOrderRecord, } from "./kernel/jobs/types.js";
|
|
38
|
-
export { BUILTIN_JOB_TASK_SLUGS } from "./kernel/jobs/types.js";
|
|
37
|
+
export type { TaskDefinition, TaskContext, TaskStep, TaskJobMeta, TaskRetryConfig, JobInstanceStatus, JobProcessingOrder, JobProcessingOrderField, JobProcessingOrderRecord, } from "./kernel/jobs/types.js";
|
|
38
|
+
export { BUILTIN_JOB_TASK_SLUGS, TaskNonRetryableError } from "./kernel/jobs/types.js";
|
|
39
|
+
export { createPassThroughTaskStep } from "./kernel/jobs/step.js";
|
|
39
40
|
export { staleJobReaperTask, runStaleJobReaper, getJobReapThresholdMs, getJobsReaperIntervalMs, } from "./kernel/jobs/reaper.js";
|
|
40
41
|
export { createLocalAPI, LocalAPI } from "./kernel/local-api.js";
|
|
41
42
|
export type { CommerceLocalAPI, LocalAPIOptions } from "./kernel/local-api.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -22,7 +22,8 @@ export { createHookContext } from "./kernel/hooks/create-context.js";
|
|
|
22
22
|
export { NullJobsAdapter } from "./kernel/jobs/adapter.js";
|
|
23
23
|
export { DrizzleJobsAdapter } from "./kernel/jobs/drizzle-adapter.js";
|
|
24
24
|
export { runPendingJobs } from "./kernel/jobs/runner.js";
|
|
25
|
-
export { BUILTIN_JOB_TASK_SLUGS } from "./kernel/jobs/types.js";
|
|
25
|
+
export { BUILTIN_JOB_TASK_SLUGS, TaskNonRetryableError } from "./kernel/jobs/types.js";
|
|
26
|
+
export { createPassThroughTaskStep } from "./kernel/jobs/step.js";
|
|
26
27
|
export { staleJobReaperTask, runStaleJobReaper, getJobReapThresholdMs, getJobsReaperIntervalMs, } from "./kernel/jobs/reaper.js";
|
|
27
28
|
export { createLocalAPI, LocalAPI } from "./kernel/local-api.js";
|
|
28
29
|
export { createCommerce } from "./runtime/commerce.js";
|
|
@@ -67,6 +67,7 @@ declare class RouteChain {
|
|
|
67
67
|
private _input;
|
|
68
68
|
private _query;
|
|
69
69
|
private _params;
|
|
70
|
+
private _output;
|
|
70
71
|
private _requireAuth;
|
|
71
72
|
private _requiredPermission;
|
|
72
73
|
constructor(method: string, fullPath: string, tag: string, routesList: PluginRouteRegistration[], pluginCtx?: {
|
|
@@ -84,6 +85,26 @@ declare class RouteChain {
|
|
|
84
85
|
query(schema: z.ZodType): this;
|
|
85
86
|
/** Override the auto-detected path parameter schema. */
|
|
86
87
|
params(schema: z.ZodType): this;
|
|
88
|
+
/**
|
|
89
|
+
* Declare the shape carried inside the `{ data }` envelope on success.
|
|
90
|
+
*
|
|
91
|
+
* Without it the route documents its payload as `any`, and every generated
|
|
92
|
+
* client sees `data?: unknown` — so a consumer has to hand-maintain a
|
|
93
|
+
* parallel schema, which is the drift the generated SDK exists to prevent.
|
|
94
|
+
*
|
|
95
|
+
* Documentation only: the handler's return value is not validated against
|
|
96
|
+
* this schema. Validating would mean either stripping unknown keys — silently
|
|
97
|
+
* changing what goes over the wire for anyone who adopts it — or throwing at
|
|
98
|
+
* runtime, turning an OpenAPI annotation into a new failure mode. A stale
|
|
99
|
+
* annotation is the cheaper wrong.
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```typescript
|
|
103
|
+
* vendors.get("/{id}").summary("Get").output(VendorSchema)
|
|
104
|
+
* .handler(async ({ params, services }) => services.vendor.get(params.id));
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
output(schema: z.ZodType): this;
|
|
87
108
|
/**
|
|
88
109
|
* Require authentication. The handler's `actor` is guaranteed non-null.
|
|
89
110
|
* Returns 401 if the request has no authenticated actor.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../../src/interfaces/rest/router.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAe,CAAC,EAAE,MAAM,mBAAmB,CAAC;AAGnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAwB/E,MAAM,WAAW,mBAAmB;IAClC,mFAAmF;IACnF,KAAK,EAAE,OAAO,CAAC;IACf,+EAA+E;IAC/E,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,0DAA0D;IAC1D,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,uFAAuF;IACvF,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,EAAE,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IAC/H,4FAA4F;IAC5F,KAAK,EAAE,MAAM,CAAC;IACd,sDAAsD;IACtD,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,gCAAgC;IAChC,EAAE,EAAE,OAAO,CAAC;IACZ,oCAAoC;IACpC,MAAM,EAAE,OAAO,CAAC;IAChB,iBAAiB;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,GAAG,EAAE,OAAO,CAAC;CACd;AAID,cAAM,UAAU;
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../../src/interfaces/rest/router.ts"],"names":[],"mappings":"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"}
|
|
@@ -56,6 +56,7 @@ class RouteChain {
|
|
|
56
56
|
_input;
|
|
57
57
|
_query;
|
|
58
58
|
_params;
|
|
59
|
+
_output;
|
|
59
60
|
_requireAuth = false;
|
|
60
61
|
_requiredPermission;
|
|
61
62
|
constructor(method, fullPath, tag, routesList, pluginCtx) {
|
|
@@ -79,6 +80,26 @@ class RouteChain {
|
|
|
79
80
|
query(schema) { this._query = schema; return this; }
|
|
80
81
|
/** Override the auto-detected path parameter schema. */
|
|
81
82
|
params(schema) { this._params = schema; return this; }
|
|
83
|
+
/**
|
|
84
|
+
* Declare the shape carried inside the `{ data }` envelope on success.
|
|
85
|
+
*
|
|
86
|
+
* Without it the route documents its payload as `any`, and every generated
|
|
87
|
+
* client sees `data?: unknown` — so a consumer has to hand-maintain a
|
|
88
|
+
* parallel schema, which is the drift the generated SDK exists to prevent.
|
|
89
|
+
*
|
|
90
|
+
* Documentation only: the handler's return value is not validated against
|
|
91
|
+
* this schema. Validating would mean either stripping unknown keys — silently
|
|
92
|
+
* changing what goes over the wire for anyone who adopts it — or throwing at
|
|
93
|
+
* runtime, turning an OpenAPI annotation into a new failure mode. A stale
|
|
94
|
+
* annotation is the cheaper wrong.
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```typescript
|
|
98
|
+
* vendors.get("/{id}").summary("Get").output(VendorSchema)
|
|
99
|
+
* .handler(async ({ params, services }) => services.vendor.get(params.id));
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
output(schema) { this._output = schema; return this; }
|
|
82
103
|
/**
|
|
83
104
|
* Require authentication. The handler's `actor` is guaranteed non-null.
|
|
84
105
|
* Returns 401 if the request has no authenticated actor.
|
|
@@ -126,7 +147,7 @@ class RouteChain {
|
|
|
126
147
|
...(this._description ? { description: this._description } : {}),
|
|
127
148
|
...(Object.keys(request).length > 0 ? { request } : {}),
|
|
128
149
|
responses: {
|
|
129
|
-
[status]: wrapJson(z.object({ data: z.any() })),
|
|
150
|
+
[status]: wrapJson(z.object({ data: this._output ?? z.any() })),
|
|
130
151
|
...errorResponses,
|
|
131
152
|
},
|
|
132
153
|
});
|
|
@@ -122,14 +122,14 @@ export declare const listFailedJobsRoute: {
|
|
|
122
122
|
tableName: "commerce_jobs";
|
|
123
123
|
dataType: "string";
|
|
124
124
|
columnType: "PgText";
|
|
125
|
-
data: "pending" | "processing" | "succeeded" | "failed";
|
|
125
|
+
data: "pending" | "processing" | "succeeded" | "failed" | "cancelled";
|
|
126
126
|
driverParam: string;
|
|
127
127
|
notNull: true;
|
|
128
128
|
hasDefault: true;
|
|
129
129
|
isPrimaryKey: false;
|
|
130
130
|
isAutoincrement: false;
|
|
131
131
|
hasRuntimeDefault: false;
|
|
132
|
-
enumValues: ["pending", "processing", "succeeded", "failed"];
|
|
132
|
+
enumValues: ["pending", "processing", "succeeded", "failed", "cancelled"];
|
|
133
133
|
baseColumn: never;
|
|
134
134
|
identity: undefined;
|
|
135
135
|
generated: undefined;
|
|
@@ -2245,14 +2245,14 @@ export declare const JobSchema: import("drizzle-zod").BuildSchema<"select", {
|
|
|
2245
2245
|
tableName: "commerce_jobs";
|
|
2246
2246
|
dataType: "string";
|
|
2247
2247
|
columnType: "PgText";
|
|
2248
|
-
data: "pending" | "processing" | "succeeded" | "failed";
|
|
2248
|
+
data: "pending" | "processing" | "succeeded" | "failed" | "cancelled";
|
|
2249
2249
|
driverParam: string;
|
|
2250
2250
|
notNull: true;
|
|
2251
2251
|
hasDefault: true;
|
|
2252
2252
|
isPrimaryKey: false;
|
|
2253
2253
|
isAutoincrement: false;
|
|
2254
2254
|
hasRuntimeDefault: false;
|
|
2255
|
-
enumValues: ["pending", "processing", "succeeded", "failed"];
|
|
2255
|
+
enumValues: ["pending", "processing", "succeeded", "failed", "cancelled"];
|
|
2256
2256
|
baseColumn: never;
|
|
2257
2257
|
identity: undefined;
|
|
2258
2258
|
generated: undefined;
|
|
@@ -4280,14 +4280,14 @@ export declare const JobListResponse: z.ZodObject<{
|
|
|
4280
4280
|
tableName: "commerce_jobs";
|
|
4281
4281
|
dataType: "string";
|
|
4282
4282
|
columnType: "PgText";
|
|
4283
|
-
data: "pending" | "processing" | "succeeded" | "failed";
|
|
4283
|
+
data: "pending" | "processing" | "succeeded" | "failed" | "cancelled";
|
|
4284
4284
|
driverParam: string;
|
|
4285
4285
|
notNull: true;
|
|
4286
4286
|
hasDefault: true;
|
|
4287
4287
|
isPrimaryKey: false;
|
|
4288
4288
|
isAutoincrement: false;
|
|
4289
4289
|
hasRuntimeDefault: false;
|
|
4290
|
-
enumValues: ["pending", "processing", "succeeded", "failed"];
|
|
4290
|
+
enumValues: ["pending", "processing", "succeeded", "failed", "cancelled"];
|
|
4291
4291
|
baseColumn: never;
|
|
4292
4292
|
identity: undefined;
|
|
4293
4293
|
generated: undefined;
|
package/dist/jobs.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { JobInstanceStatus, TaskContext, TaskDefinition, TaskJobMeta, TaskRetryConfig, TaskStep, } from "./kernel/jobs/types.js";
|
|
2
|
+
export { TaskNonRetryableError } from "./kernel/jobs/types.js";
|
|
3
|
+
export { createPassThroughTaskStep } from "./kernel/jobs/step.js";
|
|
4
|
+
export type { EnqueueOptions, ExecutionEngine, ExecutionEngineSetup, JobsAdapter, } from "./kernel/jobs/adapter.js";
|
|
5
|
+
//# sourceMappingURL=jobs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jobs.d.ts","sourceRoot":"","sources":["../src/jobs.ts"],"names":[],"mappings":"AAEA,YAAY,EACV,iBAAiB,EACjB,WAAW,EACX,cAAc,EACd,WAAW,EACX,eAAe,EACf,QAAQ,GACT,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAClE,YAAY,EACV,cAAc,EACd,eAAe,EACf,oBAAoB,EACpB,WAAW,GACZ,MAAM,0BAA0B,CAAC"}
|
package/dist/jobs.js
ADDED
|
@@ -1,7 +1,14 @@
|
|
|
1
|
-
import type { JobProcessingOrder, TaskContext, TaskDefinition } from "./types.js";
|
|
1
|
+
import type { JobInstanceStatus, JobProcessingOrder, TaskContext, TaskDefinition } from "./types.js";
|
|
2
2
|
/** Enqueue-only surface exposed to hooks and services. */
|
|
3
3
|
export interface JobsAdapter {
|
|
4
4
|
enqueue(taskSlug: string, input: Record<string, unknown>, options: EnqueueOptions): Promise<string>;
|
|
5
|
+
/** Not every engine can report instance status; absent where it cannot. */
|
|
6
|
+
status?(jobId: string): Promise<{
|
|
7
|
+
status: JobInstanceStatus;
|
|
8
|
+
error?: string;
|
|
9
|
+
}>;
|
|
10
|
+
/** Not every engine can cancel an in-flight instance; absent where it cannot. */
|
|
11
|
+
cancel?(jobId: string): Promise<void>;
|
|
5
12
|
}
|
|
6
13
|
export interface RunJobsOptions {
|
|
7
14
|
queue?: string;
|
|
@@ -34,6 +41,11 @@ export interface EnqueueOptions {
|
|
|
34
41
|
delayMs?: number;
|
|
35
42
|
concurrencyKey?: string;
|
|
36
43
|
supersedes?: boolean;
|
|
44
|
+
/** Used verbatim as the job id — the `commerce_jobs` row id on the drizzle
|
|
45
|
+
* engine, the instance id on Cloudflare Workflows — so a caller can address the
|
|
46
|
+
* job it created ("one generation, one instance"). Must be a UUID on drizzle.
|
|
47
|
+
* The pg-boss, Inngest and Trigger engines choose their own ids and ignore it. */
|
|
48
|
+
jobId?: string;
|
|
37
49
|
}
|
|
38
50
|
/**
|
|
39
51
|
* No-op enqueue surface used by isolated hook contexts.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/kernel/jobs/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,WAAW,EACX,cAAc,EACf,MAAM,YAAY,CAAC;AAEpB,0DAA0D;AAC1D,MAAM,WAAW,WAAW;IAC1B,OAAO,CACL,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,MAAM,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/kernel/jobs/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EACjB,kBAAkB,EAClB,WAAW,EACX,cAAc,EACf,MAAM,YAAY,CAAC;AAEpB,0DAA0D;AAC1D,MAAM,WAAW,WAAW;IAC1B,OAAO,CACL,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,MAAM,CAAC,CAAC;IACnB,2EAA2E;IAC3E,MAAM,CAAC,CACL,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC;QAAE,MAAM,EAAE,iBAAiB,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC1D,iFAAiF;IACjF,MAAM,CAAC,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAC3C,OAAO,EAAE,WAAW,CAAC;IACrB,eAAe,CAAC,EAAE,kBAAkB,CAAC;CACtC;AAED,MAAM,MAAM,eAAe,GACvB;IACE,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;CACvD,GACD;IACE,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEN,uEAAuE;AACvE,MAAM,WAAW,eAAgB,SAAQ,WAAW;IAClD,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,oBAAoB,GAAG,IAAI,CAAC;CAC7C;AAED,MAAM,WAAW,cAAc;IAC7B,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;sFAGkF;IAClF,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,qBAAa,eAAgB,YAAW,WAAW;IAC3C,OAAO,CACX,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,QAAQ,EAAE,cAAc,GACvB,OAAO,CAAC,MAAM,CAAC;CAGnB"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { DrizzleDatabase } from "../database/drizzle-db.js";
|
|
2
|
-
import type { TaskDefinition } from "./types.js";
|
|
2
|
+
import type { JobInstanceStatus, TaskDefinition } from "./types.js";
|
|
3
3
|
import type { EnqueueOptions, ExecutionEngine, ExecutionEngineSetup, RunJobsOptions } from "./adapter.js";
|
|
4
4
|
/**
|
|
5
5
|
* PostgreSQL-backed job queue adapter using the application's own database.
|
|
@@ -21,5 +21,13 @@ export declare class DrizzleJobsAdapter implements ExecutionEngine {
|
|
|
21
21
|
constructor(db: DrizzleDatabase, tasks?: Map<string, TaskDefinition>);
|
|
22
22
|
register(setup: ExecutionEngineSetup): void;
|
|
23
23
|
enqueue(taskSlug: string, input: Record<string, unknown>, options: EnqueueOptions): Promise<string>;
|
|
24
|
+
status(jobId: string): Promise<{
|
|
25
|
+
status: JobInstanceStatus;
|
|
26
|
+
error?: string;
|
|
27
|
+
}>;
|
|
28
|
+
/** Cancels a job that has not started yet; a job already `processing` (or
|
|
29
|
+
* finished) cannot be interrupted from here and is left untouched. The row is
|
|
30
|
+
* kept so `status()` reports it as `terminated`. */
|
|
31
|
+
cancel(jobId: string): Promise<void>;
|
|
24
32
|
}
|
|
25
33
|
//# sourceMappingURL=drizzle-adapter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drizzle-adapter.d.ts","sourceRoot":"","sources":["../../../src/kernel/jobs/drizzle-adapter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"drizzle-adapter.d.ts","sourceRoot":"","sources":["../../../src/kernel/jobs/drizzle-adapter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACpE,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EACf,oBAAoB,EACpB,cAAc,EACf,MAAM,cAAc,CAAC;AAUtB;;;;GAIG;AACH,qBAAa,kBAAmB,YAAW,eAAe;IA4CtD,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,KAAK;IA5Cf,OAAO,CAAC,KAAK,CAAmC;IAChD,OAAO,CAAC,oBAAoB,CAAK;IAEjC,QAAQ,CAAC,SAAS;;wBAEK,cAAc;;;;MAmCnC;gBAGQ,EAAE,EAAE,eAAe,EACnB,KAAK,GAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAa;IAGxD,QAAQ,CAAC,KAAK,EAAE,oBAAoB,GAAG,IAAI;IAKrC,OAAO,CACX,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,MAAM,CAAC;IAiDZ,MAAM,CACV,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC;QAAE,MAAM,EAAE,iBAAiB,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAezD;;wDAEoD;IAC9C,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAQ3C"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { eq, and } from "drizzle-orm";
|
|
2
|
-
import { OrgResolutionError } from "../errors.js";
|
|
2
|
+
import { OrgResolutionError, CommerceNotFoundError } from "../errors.js";
|
|
3
3
|
import { commerceJobs } from "./schema.js";
|
|
4
4
|
import { runPendingJobs } from "./runner.js";
|
|
5
5
|
import { getJobReapThresholdMs, getJobsReaperIntervalMs, runStaleJobReaper, } from "./reaper.js";
|
|
@@ -71,6 +71,7 @@ export class DrizzleJobsAdapter {
|
|
|
71
71
|
const rows = await this.db
|
|
72
72
|
.insert(commerceJobs)
|
|
73
73
|
.values({
|
|
74
|
+
...(options.jobId ? { id: options.jobId } : {}),
|
|
74
75
|
organizationId,
|
|
75
76
|
taskSlug,
|
|
76
77
|
input,
|
|
@@ -84,4 +85,34 @@ export class DrizzleJobsAdapter {
|
|
|
84
85
|
.returning({ id: commerceJobs.id });
|
|
85
86
|
return rows[0].id;
|
|
86
87
|
}
|
|
88
|
+
async status(jobId) {
|
|
89
|
+
const [row] = await this.db
|
|
90
|
+
.select()
|
|
91
|
+
.from(commerceJobs)
|
|
92
|
+
.where(eq(commerceJobs.id, jobId))
|
|
93
|
+
.limit(1);
|
|
94
|
+
if (!row) {
|
|
95
|
+
throw new CommerceNotFoundError(`No job found for id ${jobId}`);
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
status: DRIZZLE_JOB_STATUS_MAP[row.status],
|
|
99
|
+
...(row.error !== null ? { error: row.error } : {}),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/** Cancels a job that has not started yet; a job already `processing` (or
|
|
103
|
+
* finished) cannot be interrupted from here and is left untouched. The row is
|
|
104
|
+
* kept so `status()` reports it as `terminated`. */
|
|
105
|
+
async cancel(jobId) {
|
|
106
|
+
await this.db
|
|
107
|
+
.update(commerceJobs)
|
|
108
|
+
.set({ status: "cancelled" })
|
|
109
|
+
.where(and(eq(commerceJobs.id, jobId), eq(commerceJobs.status, "pending")));
|
|
110
|
+
}
|
|
87
111
|
}
|
|
112
|
+
const DRIZZLE_JOB_STATUS_MAP = {
|
|
113
|
+
pending: "queued",
|
|
114
|
+
processing: "running",
|
|
115
|
+
succeeded: "complete",
|
|
116
|
+
failed: "errored",
|
|
117
|
+
cancelled: "terminated",
|
|
118
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../../src/kernel/jobs/runner.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../../src/kernel/jobs/runner.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAKrE,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,eAAe,CAAC;IACpB,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,kBAAkB,CAAC;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,gBAAgB,CAAC;CAC5B;AA4CD;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAoNhD"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { eq, and, sql } from "drizzle-orm";
|
|
2
|
+
import { TaskNonRetryableError } from "./types.js";
|
|
3
|
+
import { createPassThroughTaskStep } from "./step.js";
|
|
2
4
|
import { commerceJobs } from "./schema.js";
|
|
3
5
|
function isExclusiveTask(task) {
|
|
4
6
|
return Boolean(task?.concurrency && task.concurrency.exclusive !== false);
|
|
@@ -115,6 +117,7 @@ export async function runPendingJobs(args) {
|
|
|
115
117
|
return jobsToRun.sort(compareByProcessingOrder(processingOrder));
|
|
116
118
|
});
|
|
117
119
|
// Phase 2: Execute each claimed job outside the claim transaction
|
|
120
|
+
const step = createPassThroughTaskStep();
|
|
118
121
|
const outcomes = await Promise.all(claimed.map(async (job) => {
|
|
119
122
|
const task = tasks.get(job.taskSlug);
|
|
120
123
|
if (!task) {
|
|
@@ -136,7 +139,7 @@ export async function runPendingJobs(args) {
|
|
|
136
139
|
try {
|
|
137
140
|
const result = await task.handler({
|
|
138
141
|
input: job.input,
|
|
139
|
-
ctx: { logger, db, services },
|
|
142
|
+
ctx: { logger, db, services, step },
|
|
140
143
|
job: {
|
|
141
144
|
attemptNumber: job.attempts + 1,
|
|
142
145
|
maxAttempts: job.maxAttempts,
|
|
@@ -162,7 +165,8 @@ export async function runPendingJobs(args) {
|
|
|
162
165
|
});
|
|
163
166
|
const attempts = job.attempts + 1;
|
|
164
167
|
const maxAttempts = job.maxAttempts;
|
|
165
|
-
|
|
168
|
+
const nonRetryable = err instanceof TaskNonRetryableError;
|
|
169
|
+
if (nonRetryable || attempts >= maxAttempts) {
|
|
166
170
|
await db
|
|
167
171
|
.update(commerceJobs)
|
|
168
172
|
.set({
|
|
@@ -109,14 +109,14 @@ export declare const commerceJobs: import("drizzle-orm/pg-core").PgTableWithColu
|
|
|
109
109
|
tableName: "commerce_jobs";
|
|
110
110
|
dataType: "string";
|
|
111
111
|
columnType: "PgText";
|
|
112
|
-
data: "pending" | "processing" | "succeeded" | "failed";
|
|
112
|
+
data: "pending" | "processing" | "succeeded" | "failed" | "cancelled";
|
|
113
113
|
driverParam: string;
|
|
114
114
|
notNull: true;
|
|
115
115
|
hasDefault: true;
|
|
116
116
|
isPrimaryKey: false;
|
|
117
117
|
isAutoincrement: false;
|
|
118
118
|
hasRuntimeDefault: false;
|
|
119
|
-
enumValues: ["pending", "processing", "succeeded", "failed"];
|
|
119
|
+
enumValues: ["pending", "processing", "succeeded", "failed", "cancelled"];
|
|
120
120
|
baseColumn: never;
|
|
121
121
|
identity: undefined;
|
|
122
122
|
generated: undefined;
|
|
@@ -10,7 +10,7 @@ export const commerceJobs = pgTable("commerce_jobs", {
|
|
|
10
10
|
input: jsonb("input").notNull().default("{}"),
|
|
11
11
|
output: jsonb("output"),
|
|
12
12
|
status: text("status", {
|
|
13
|
-
enum: ["pending", "processing", "succeeded", "failed"],
|
|
13
|
+
enum: ["pending", "processing", "succeeded", "failed", "cancelled"],
|
|
14
14
|
})
|
|
15
15
|
.notNull()
|
|
16
16
|
.default("pending"),
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { TaskStep } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Pass-through `TaskStep` for pull-based engines with no durable step primitive:
|
|
4
|
+
* `do` runs `fn` immediately, `sleep` waits in-process. Lets a handler written
|
|
5
|
+
* against `ctx.step` run unchanged on the drizzle engine.
|
|
6
|
+
*/
|
|
7
|
+
export declare function createPassThroughTaskStep(): TaskStep;
|
|
8
|
+
//# sourceMappingURL=step.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"step.d.ts","sourceRoot":"","sources":["../../../src/kernel/jobs/step.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C;;;;GAIG;AACH,wBAAgB,yBAAyB,IAAI,QAAQ,CAkBpD"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { TaskNonRetryableError } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Pass-through `TaskStep` for pull-based engines with no durable step primitive:
|
|
4
|
+
* `do` runs `fn` immediately, `sleep` waits in-process. Lets a handler written
|
|
5
|
+
* against `ctx.step` run unchanged on the drizzle engine.
|
|
6
|
+
*/
|
|
7
|
+
export function createPassThroughTaskStep() {
|
|
8
|
+
return {
|
|
9
|
+
async do(_name, fn, options) {
|
|
10
|
+
try {
|
|
11
|
+
return await fn();
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
if (options?.nonRetryable && !(error instanceof TaskNonRetryableError)) {
|
|
15
|
+
throw new TaskNonRetryableError(error instanceof Error ? error.message : String(error));
|
|
16
|
+
}
|
|
17
|
+
throw error;
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
async sleep(_name, ms) {
|
|
21
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
}
|
|
@@ -8,7 +8,27 @@ export interface TaskContext {
|
|
|
8
8
|
logger: Logger;
|
|
9
9
|
db: DrizzleDatabase;
|
|
10
10
|
services: ServiceContainer;
|
|
11
|
+
/** Durable per-phase execution, backed by the Workflow step on Cloudflare and a
|
|
12
|
+
* pass-through implementation on the drizzle engine. Absent on engines (pg-boss,
|
|
13
|
+
* Inngest, Trigger) that have not wired one; a handler that ignores it runs as before. */
|
|
14
|
+
step?: TaskStep;
|
|
11
15
|
}
|
|
16
|
+
/** Durable, idempotent execution of one phase of a task handler. */
|
|
17
|
+
export interface TaskStep {
|
|
18
|
+
do<T>(name: string, fn: () => Promise<T>, options?: {
|
|
19
|
+
retries?: TaskRetryConfig;
|
|
20
|
+
timeout?: number;
|
|
21
|
+
nonRetryable?: boolean;
|
|
22
|
+
}): Promise<T>;
|
|
23
|
+
sleep(name: string, ms: number): Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
/** Thrown by a task handler (or a step's callback) to signal the failure must not be
|
|
26
|
+
* retried — the Cloudflare engine maps it to `NonRetryableError`; the drizzle runner
|
|
27
|
+
* fails the job immediately regardless of remaining attempts. */
|
|
28
|
+
export declare class TaskNonRetryableError extends Error {
|
|
29
|
+
constructor(message: string);
|
|
30
|
+
}
|
|
31
|
+
export type JobInstanceStatus = "queued" | "running" | "waiting" | "complete" | "errored" | "terminated";
|
|
12
32
|
export interface TaskRetryConfig {
|
|
13
33
|
attempts: number;
|
|
14
34
|
backoff?: {
|
|
@@ -44,6 +64,13 @@ export interface TaskDefinition<TInput extends Record<string, unknown> = Record<
|
|
|
44
64
|
output: TOutput;
|
|
45
65
|
}>;
|
|
46
66
|
retries?: TaskRetryConfig;
|
|
67
|
+
/** The handler drives its own durable phases through `ctx.step` and keeps every
|
|
68
|
+
* side effect inside one. A push engine with a step primitive (Cloudflare) then
|
|
69
|
+
* runs the handler directly — each `ctx.step.do` is a real step with its own
|
|
70
|
+
* retries and `retries` above is only the per-step default — instead of
|
|
71
|
+
* wrapping the whole handler in one retried unit; `job.attemptNumber` is then
|
|
72
|
+
* always 1, because retries happen per step. Pull engines ignore it. */
|
|
73
|
+
durableSteps?: boolean;
|
|
47
74
|
concurrency?: {
|
|
48
75
|
key: (input: TInput) => string;
|
|
49
76
|
exclusive?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/kernel/jobs/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAEjE,eAAO,MAAM,sBAAsB;;;CAGzB,CAAC;AAEX,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,eAAe,CAAC;IACpB,QAAQ,EAAE,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/kernel/jobs/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,3 +2,12 @@ export const BUILTIN_JOB_TASK_SLUGS = {
|
|
|
2
2
|
webhookDeliver: "webhooks/deliver",
|
|
3
3
|
staleJobReaper: "jobs/reap-stale",
|
|
4
4
|
};
|
|
5
|
+
/** Thrown by a task handler (or a step's callback) to signal the failure must not be
|
|
6
|
+
* retried — the Cloudflare engine maps it to `NonRetryableError`; the drizzle runner
|
|
7
|
+
* fails the job immediately regardless of remaining attempts. */
|
|
8
|
+
export class TaskNonRetryableError extends Error {
|
|
9
|
+
constructor(message) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = "TaskNonRetryableError";
|
|
12
|
+
}
|
|
13
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@porulle/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -33,6 +33,12 @@
|
|
|
33
33
|
"bun": "./src/drizzle.ts",
|
|
34
34
|
"import": "./dist/drizzle.js",
|
|
35
35
|
"require": "./dist/drizzle.js"
|
|
36
|
+
},
|
|
37
|
+
"./jobs": {
|
|
38
|
+
"types": "./src/jobs.ts",
|
|
39
|
+
"bun": "./src/jobs.ts",
|
|
40
|
+
"import": "./dist/jobs.js",
|
|
41
|
+
"require": "./dist/jobs.js"
|
|
36
42
|
}
|
|
37
43
|
},
|
|
38
44
|
"dependencies": {
|
package/src/index.ts
CHANGED
|
@@ -84,13 +84,16 @@ export type { RunPendingJobsArgs } from "./kernel/jobs/runner.js";
|
|
|
84
84
|
export type {
|
|
85
85
|
TaskDefinition,
|
|
86
86
|
TaskContext,
|
|
87
|
+
TaskStep,
|
|
87
88
|
TaskJobMeta,
|
|
88
89
|
TaskRetryConfig,
|
|
90
|
+
JobInstanceStatus,
|
|
89
91
|
JobProcessingOrder,
|
|
90
92
|
JobProcessingOrderField,
|
|
91
93
|
JobProcessingOrderRecord,
|
|
92
94
|
} from "./kernel/jobs/types.js";
|
|
93
|
-
export { BUILTIN_JOB_TASK_SLUGS } from "./kernel/jobs/types.js";
|
|
95
|
+
export { BUILTIN_JOB_TASK_SLUGS, TaskNonRetryableError } from "./kernel/jobs/types.js";
|
|
96
|
+
export { createPassThroughTaskStep } from "./kernel/jobs/step.js";
|
|
94
97
|
export {
|
|
95
98
|
staleJobReaperTask,
|
|
96
99
|
runStaleJobReaper,
|
|
@@ -85,6 +85,7 @@ class RouteChain {
|
|
|
85
85
|
private _input: z.ZodType | undefined;
|
|
86
86
|
private _query: z.ZodType | undefined;
|
|
87
87
|
private _params: z.ZodType | undefined;
|
|
88
|
+
private _output: z.ZodType | undefined;
|
|
88
89
|
private _requireAuth = false;
|
|
89
90
|
private _requiredPermission: string | undefined;
|
|
90
91
|
constructor(
|
|
@@ -117,6 +118,27 @@ class RouteChain {
|
|
|
117
118
|
/** Override the auto-detected path parameter schema. */
|
|
118
119
|
params(schema: z.ZodType) { this._params = schema; return this; }
|
|
119
120
|
|
|
121
|
+
/**
|
|
122
|
+
* Declare the shape carried inside the `{ data }` envelope on success.
|
|
123
|
+
*
|
|
124
|
+
* Without it the route documents its payload as `any`, and every generated
|
|
125
|
+
* client sees `data?: unknown` — so a consumer has to hand-maintain a
|
|
126
|
+
* parallel schema, which is the drift the generated SDK exists to prevent.
|
|
127
|
+
*
|
|
128
|
+
* Documentation only: the handler's return value is not validated against
|
|
129
|
+
* this schema. Validating would mean either stripping unknown keys — silently
|
|
130
|
+
* changing what goes over the wire for anyone who adopts it — or throwing at
|
|
131
|
+
* runtime, turning an OpenAPI annotation into a new failure mode. A stale
|
|
132
|
+
* annotation is the cheaper wrong.
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```typescript
|
|
136
|
+
* vendors.get("/{id}").summary("Get").output(VendorSchema)
|
|
137
|
+
* .handler(async ({ params, services }) => services.vendor.get(params.id));
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
output(schema: z.ZodType) { this._output = schema; return this; }
|
|
141
|
+
|
|
120
142
|
/**
|
|
121
143
|
* Require authentication. The handler's `actor` is guaranteed non-null.
|
|
122
144
|
* Returns 401 if the request has no authenticated actor.
|
|
@@ -165,7 +187,7 @@ class RouteChain {
|
|
|
165
187
|
...(this._description ? { description: this._description } : {}),
|
|
166
188
|
...(Object.keys(request).length > 0 ? { request } : {}),
|
|
167
189
|
responses: {
|
|
168
|
-
[status]: wrapJson(z.object({ data: z.any() })),
|
|
190
|
+
[status]: wrapJson(z.object({ data: this._output ?? z.any() })),
|
|
169
191
|
...errorResponses,
|
|
170
192
|
},
|
|
171
193
|
});
|
package/src/jobs.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Leaf entry for execution engines that run outside Node (Cloudflare Workers):
|
|
2
|
+
// only the job types and the two runtime helpers, none of the server runtime.
|
|
3
|
+
export type {
|
|
4
|
+
JobInstanceStatus,
|
|
5
|
+
TaskContext,
|
|
6
|
+
TaskDefinition,
|
|
7
|
+
TaskJobMeta,
|
|
8
|
+
TaskRetryConfig,
|
|
9
|
+
TaskStep,
|
|
10
|
+
} from "./kernel/jobs/types.js";
|
|
11
|
+
export { TaskNonRetryableError } from "./kernel/jobs/types.js";
|
|
12
|
+
export { createPassThroughTaskStep } from "./kernel/jobs/step.js";
|
|
13
|
+
export type {
|
|
14
|
+
EnqueueOptions,
|
|
15
|
+
ExecutionEngine,
|
|
16
|
+
ExecutionEngineSetup,
|
|
17
|
+
JobsAdapter,
|
|
18
|
+
} from "./kernel/jobs/adapter.js";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type {
|
|
2
|
+
JobInstanceStatus,
|
|
2
3
|
JobProcessingOrder,
|
|
3
4
|
TaskContext,
|
|
4
5
|
TaskDefinition,
|
|
@@ -11,6 +12,12 @@ export interface JobsAdapter {
|
|
|
11
12
|
input: Record<string, unknown>,
|
|
12
13
|
options: EnqueueOptions,
|
|
13
14
|
): Promise<string>;
|
|
15
|
+
/** Not every engine can report instance status; absent where it cannot. */
|
|
16
|
+
status?(
|
|
17
|
+
jobId: string,
|
|
18
|
+
): Promise<{ status: JobInstanceStatus; error?: string }>;
|
|
19
|
+
/** Not every engine can cancel an in-flight instance; absent where it cannot. */
|
|
20
|
+
cancel?(jobId: string): Promise<void>;
|
|
14
21
|
}
|
|
15
22
|
|
|
16
23
|
export interface RunJobsOptions {
|
|
@@ -51,6 +58,11 @@ export interface EnqueueOptions {
|
|
|
51
58
|
delayMs?: number;
|
|
52
59
|
concurrencyKey?: string;
|
|
53
60
|
supersedes?: boolean;
|
|
61
|
+
/** Used verbatim as the job id — the `commerce_jobs` row id on the drizzle
|
|
62
|
+
* engine, the instance id on Cloudflare Workflows — so a caller can address the
|
|
63
|
+
* job it created ("one generation, one instance"). Must be a UUID on drizzle.
|
|
64
|
+
* The pg-boss, Inngest and Trigger engines choose their own ids and ignore it. */
|
|
65
|
+
jobId?: string;
|
|
54
66
|
}
|
|
55
67
|
|
|
56
68
|
/**
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { eq, and } from "drizzle-orm";
|
|
2
2
|
import type { DrizzleDatabase } from "../database/drizzle-db.js";
|
|
3
|
-
import type { TaskDefinition } from "./types.js";
|
|
3
|
+
import type { JobInstanceStatus, TaskDefinition } from "./types.js";
|
|
4
4
|
import type {
|
|
5
5
|
EnqueueOptions,
|
|
6
6
|
ExecutionEngine,
|
|
7
7
|
ExecutionEngineSetup,
|
|
8
8
|
RunJobsOptions,
|
|
9
9
|
} from "./adapter.js";
|
|
10
|
-
import { OrgResolutionError } from "../errors.js";
|
|
10
|
+
import { OrgResolutionError, CommerceNotFoundError } from "../errors.js";
|
|
11
11
|
import { commerceJobs } from "./schema.js";
|
|
12
12
|
import { runPendingJobs } from "./runner.js";
|
|
13
13
|
import {
|
|
@@ -111,6 +111,7 @@ export class DrizzleJobsAdapter implements ExecutionEngine {
|
|
|
111
111
|
const rows = await this.db
|
|
112
112
|
.insert(commerceJobs)
|
|
113
113
|
.values({
|
|
114
|
+
...(options.jobId ? { id: options.jobId } : {}),
|
|
114
115
|
organizationId,
|
|
115
116
|
taskSlug,
|
|
116
117
|
input,
|
|
@@ -125,4 +126,44 @@ export class DrizzleJobsAdapter implements ExecutionEngine {
|
|
|
125
126
|
|
|
126
127
|
return rows[0]!.id;
|
|
127
128
|
}
|
|
129
|
+
|
|
130
|
+
async status(
|
|
131
|
+
jobId: string,
|
|
132
|
+
): Promise<{ status: JobInstanceStatus; error?: string }> {
|
|
133
|
+
const [row] = await this.db
|
|
134
|
+
.select()
|
|
135
|
+
.from(commerceJobs)
|
|
136
|
+
.where(eq(commerceJobs.id, jobId))
|
|
137
|
+
.limit(1);
|
|
138
|
+
if (!row) {
|
|
139
|
+
throw new CommerceNotFoundError(`No job found for id ${jobId}`);
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
status: DRIZZLE_JOB_STATUS_MAP[row.status],
|
|
143
|
+
...(row.error !== null ? { error: row.error } : {}),
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** Cancels a job that has not started yet; a job already `processing` (or
|
|
148
|
+
* finished) cannot be interrupted from here and is left untouched. The row is
|
|
149
|
+
* kept so `status()` reports it as `terminated`. */
|
|
150
|
+
async cancel(jobId: string): Promise<void> {
|
|
151
|
+
await this.db
|
|
152
|
+
.update(commerceJobs)
|
|
153
|
+
.set({ status: "cancelled" })
|
|
154
|
+
.where(
|
|
155
|
+
and(eq(commerceJobs.id, jobId), eq(commerceJobs.status, "pending")),
|
|
156
|
+
);
|
|
157
|
+
}
|
|
128
158
|
}
|
|
159
|
+
|
|
160
|
+
const DRIZZLE_JOB_STATUS_MAP: Record<
|
|
161
|
+
"pending" | "processing" | "succeeded" | "failed" | "cancelled",
|
|
162
|
+
JobInstanceStatus
|
|
163
|
+
> = {
|
|
164
|
+
pending: "queued",
|
|
165
|
+
processing: "running",
|
|
166
|
+
succeeded: "complete",
|
|
167
|
+
failed: "errored",
|
|
168
|
+
cancelled: "terminated",
|
|
169
|
+
};
|
|
@@ -2,6 +2,8 @@ import { eq, and, sql } from "drizzle-orm";
|
|
|
2
2
|
import type { DrizzleDatabase } from "../database/drizzle-db.js";
|
|
3
3
|
import type { Logger, ServiceContainer } from "../hooks/types.js";
|
|
4
4
|
import type { JobProcessingOrder, TaskDefinition } from "./types.js";
|
|
5
|
+
import { TaskNonRetryableError } from "./types.js";
|
|
6
|
+
import { createPassThroughTaskStep } from "./step.js";
|
|
5
7
|
import { commerceJobs } from "./schema.js";
|
|
6
8
|
|
|
7
9
|
export interface RunPendingJobsArgs {
|
|
@@ -180,6 +182,7 @@ export async function runPendingJobs(
|
|
|
180
182
|
});
|
|
181
183
|
|
|
182
184
|
// Phase 2: Execute each claimed job outside the claim transaction
|
|
185
|
+
const step = createPassThroughTaskStep();
|
|
183
186
|
const outcomes = await Promise.all(
|
|
184
187
|
claimed.map(async (job) => {
|
|
185
188
|
const task = tasks.get(job.taskSlug);
|
|
@@ -207,7 +210,7 @@ export async function runPendingJobs(
|
|
|
207
210
|
try {
|
|
208
211
|
const result = await task.handler({
|
|
209
212
|
input: job.input as Record<string, unknown>,
|
|
210
|
-
ctx: { logger, db, services },
|
|
213
|
+
ctx: { logger, db, services, step },
|
|
211
214
|
job: {
|
|
212
215
|
attemptNumber: job.attempts + 1,
|
|
213
216
|
maxAttempts: job.maxAttempts,
|
|
@@ -234,8 +237,9 @@ export async function runPendingJobs(
|
|
|
234
237
|
});
|
|
235
238
|
const attempts = job.attempts + 1;
|
|
236
239
|
const maxAttempts = job.maxAttempts;
|
|
240
|
+
const nonRetryable = err instanceof TaskNonRetryableError;
|
|
237
241
|
|
|
238
|
-
if (attempts >= maxAttempts) {
|
|
242
|
+
if (nonRetryable || attempts >= maxAttempts) {
|
|
239
243
|
await db
|
|
240
244
|
.update(commerceJobs)
|
|
241
245
|
.set({
|
|
@@ -19,7 +19,7 @@ export const commerceJobs = pgTable("commerce_jobs", {
|
|
|
19
19
|
input: jsonb("input").notNull().default("{}"),
|
|
20
20
|
output: jsonb("output"),
|
|
21
21
|
status: text("status", {
|
|
22
|
-
enum: ["pending", "processing", "succeeded", "failed"],
|
|
22
|
+
enum: ["pending", "processing", "succeeded", "failed", "cancelled"],
|
|
23
23
|
})
|
|
24
24
|
.notNull()
|
|
25
25
|
.default("pending"),
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { TaskNonRetryableError } from "./types.js";
|
|
2
|
+
import type { TaskStep } from "./types.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Pass-through `TaskStep` for pull-based engines with no durable step primitive:
|
|
6
|
+
* `do` runs `fn` immediately, `sleep` waits in-process. Lets a handler written
|
|
7
|
+
* against `ctx.step` run unchanged on the drizzle engine.
|
|
8
|
+
*/
|
|
9
|
+
export function createPassThroughTaskStep(): TaskStep {
|
|
10
|
+
return {
|
|
11
|
+
async do(_name, fn, options) {
|
|
12
|
+
try {
|
|
13
|
+
return await fn();
|
|
14
|
+
} catch (error) {
|
|
15
|
+
if (options?.nonRetryable && !(error instanceof TaskNonRetryableError)) {
|
|
16
|
+
throw new TaskNonRetryableError(
|
|
17
|
+
error instanceof Error ? error.message : String(error),
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
throw error;
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
async sleep(_name, ms) {
|
|
24
|
+
await new Promise<void>((resolve) => setTimeout(resolve, ms));
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
}
|
package/src/kernel/jobs/types.ts
CHANGED
|
@@ -10,8 +10,44 @@ export interface TaskContext {
|
|
|
10
10
|
logger: Logger;
|
|
11
11
|
db: DrizzleDatabase;
|
|
12
12
|
services: ServiceContainer;
|
|
13
|
+
/** Durable per-phase execution, backed by the Workflow step on Cloudflare and a
|
|
14
|
+
* pass-through implementation on the drizzle engine. Absent on engines (pg-boss,
|
|
15
|
+
* Inngest, Trigger) that have not wired one; a handler that ignores it runs as before. */
|
|
16
|
+
step?: TaskStep;
|
|
13
17
|
}
|
|
14
18
|
|
|
19
|
+
/** Durable, idempotent execution of one phase of a task handler. */
|
|
20
|
+
export interface TaskStep {
|
|
21
|
+
do<T>(
|
|
22
|
+
name: string,
|
|
23
|
+
fn: () => Promise<T>,
|
|
24
|
+
options?: {
|
|
25
|
+
retries?: TaskRetryConfig;
|
|
26
|
+
timeout?: number;
|
|
27
|
+
nonRetryable?: boolean;
|
|
28
|
+
},
|
|
29
|
+
): Promise<T>;
|
|
30
|
+
sleep(name: string, ms: number): Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Thrown by a task handler (or a step's callback) to signal the failure must not be
|
|
34
|
+
* retried — the Cloudflare engine maps it to `NonRetryableError`; the drizzle runner
|
|
35
|
+
* fails the job immediately regardless of remaining attempts. */
|
|
36
|
+
export class TaskNonRetryableError extends Error {
|
|
37
|
+
constructor(message: string) {
|
|
38
|
+
super(message);
|
|
39
|
+
this.name = "TaskNonRetryableError";
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export type JobInstanceStatus =
|
|
44
|
+
| "queued"
|
|
45
|
+
| "running"
|
|
46
|
+
| "waiting"
|
|
47
|
+
| "complete"
|
|
48
|
+
| "errored"
|
|
49
|
+
| "terminated";
|
|
50
|
+
|
|
15
51
|
export interface TaskRetryConfig {
|
|
16
52
|
attempts: number;
|
|
17
53
|
backoff?: { type: "fixed" | "exponential"; delay: number };
|
|
@@ -59,6 +95,13 @@ export interface TaskDefinition<
|
|
|
59
95
|
job?: TaskJobMeta;
|
|
60
96
|
}) => Promise<{ output: TOutput }>;
|
|
61
97
|
retries?: TaskRetryConfig;
|
|
98
|
+
/** The handler drives its own durable phases through `ctx.step` and keeps every
|
|
99
|
+
* side effect inside one. A push engine with a step primitive (Cloudflare) then
|
|
100
|
+
* runs the handler directly — each `ctx.step.do` is a real step with its own
|
|
101
|
+
* retries and `retries` above is only the per-step default — instead of
|
|
102
|
+
* wrapping the whole handler in one retried unit; `job.attemptNumber` is then
|
|
103
|
+
* always 1, because retries happen per step. Pull engines ignore it. */
|
|
104
|
+
durableSteps?: boolean;
|
|
62
105
|
concurrency?: {
|
|
63
106
|
key: (input: TInput) => string;
|
|
64
107
|
exclusive?: boolean;
|