do-jobs 0.0.1 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +120 -0
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# do-jobs
|
|
2
|
+
|
|
3
|
+
Type-safe delayed and interval jobs for Cloudflare Durable Objects.
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
### 1. Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add do-jobs zod
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
`do-jobs` validates job payloads with the [Standard Schema](https://standardschema.dev/) interface, so you can use libraries like Zod.
|
|
14
|
+
|
|
15
|
+
### 2. Define jobs and wire your Durable Object
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { createDefineJob, setupJobs, type JobRuntime } from "do-jobs";
|
|
19
|
+
import { z } from "zod";
|
|
20
|
+
|
|
21
|
+
type Env = {
|
|
22
|
+
WEBHOOK_URL: string;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const defineJob = createDefineJob<{ env: Env }>();
|
|
26
|
+
|
|
27
|
+
const sendWebhook = defineJob({ type: "send-webhook" })
|
|
28
|
+
.input(
|
|
29
|
+
z.object({
|
|
30
|
+
message: z.string().min(1),
|
|
31
|
+
}),
|
|
32
|
+
)
|
|
33
|
+
.handler(async ({ input, context, job }) => {
|
|
34
|
+
await fetch(context.env.WEBHOOK_URL, {
|
|
35
|
+
method: "POST",
|
|
36
|
+
headers: { "content-type": "application/json" },
|
|
37
|
+
body: JSON.stringify({ id: job.id, message: input.message }),
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
export class JobsDO extends DurableObject<Env> {
|
|
42
|
+
private runtimePromise: Promise<JobRuntime>;
|
|
43
|
+
|
|
44
|
+
constructor(ctx: DurableObjectState, env: Env) {
|
|
45
|
+
super(ctx, env);
|
|
46
|
+
this.runtimePromise = setupJobs({
|
|
47
|
+
ctx,
|
|
48
|
+
context: { env },
|
|
49
|
+
jobs: [sendWebhook],
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async fetch(request: Request): Promise<Response> {
|
|
54
|
+
const runtime = await this.runtimePromise;
|
|
55
|
+
const url = new URL(request.url);
|
|
56
|
+
|
|
57
|
+
if (url.pathname === "/enqueue") {
|
|
58
|
+
await runtime.schedule(sendWebhook, {
|
|
59
|
+
input: { message: "hello" },
|
|
60
|
+
at: Date.now() + 5_000,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
return new Response("queued", { status: 202 });
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return new Response("not found", { status: 404 });
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async alarm(): Promise<void> {
|
|
70
|
+
const runtime = await this.runtimePromise;
|
|
71
|
+
await runtime.onAlarm();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Docs
|
|
77
|
+
|
|
78
|
+
### `createDefineJob<TContext>()`
|
|
79
|
+
|
|
80
|
+
Creates a typed builder for declaring jobs.
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
const defineJob = createDefineJob<{ env: Env }>();
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
A job definition requires:
|
|
87
|
+
- `type`: unique string identifier.
|
|
88
|
+
- `input(schema)`: any Standard Schema compatible validator.
|
|
89
|
+
- `handler(({ input, context, job }) => ...)`: execution function.
|
|
90
|
+
|
|
91
|
+
### `setupJobs({ jobs, ctx, context, maxJobsPerAlarm? })`
|
|
92
|
+
|
|
93
|
+
Initializes runtime state and returns a `JobRuntime`.
|
|
94
|
+
|
|
95
|
+
- `jobs`: list of registered job definitions.
|
|
96
|
+
- `ctx`: Durable Object state.
|
|
97
|
+
- `context`: object injected into every handler.
|
|
98
|
+
- `maxJobsPerAlarm` (default `50`): upper bound of jobs executed per alarm tick.
|
|
99
|
+
|
|
100
|
+
`setupJobs(...)` also:
|
|
101
|
+
- creates/migrates internal SQLite tables,
|
|
102
|
+
- recalculates the next Durable Object alarm.
|
|
103
|
+
|
|
104
|
+
### `JobRuntime`
|
|
105
|
+
|
|
106
|
+
`setupJobs(...)` returns methods:
|
|
107
|
+
|
|
108
|
+
- `onAlarm()`: run due jobs and schedule the next alarm.
|
|
109
|
+
- `setNextAlarm()`: force recalculation of next alarm time.
|
|
110
|
+
- `schedule(job, { input, at })`: queue a one-off run.
|
|
111
|
+
- `scheduleInterval(job, { input, dedupeKey, everyMs, startAt? })`: create/update an interval schedule.
|
|
112
|
+
- `cancelInterval(job, { dedupeKey })`: cancel a previously scheduled interval.
|
|
113
|
+
|
|
114
|
+
### Behavior Notes
|
|
115
|
+
|
|
116
|
+
- Inputs are validated before enqueueing and again before handler execution.
|
|
117
|
+
- Persisted payloads must remain valid after JSON serialization.
|
|
118
|
+
- Interval jobs are deduplicated by `(job.type, dedupeKey)`.
|
|
119
|
+
- Failed handlers are marked as `failed` and store error message/stack.
|
|
120
|
+
- Job statuses: `queued`, `running`, `completed`, `failed`, `cancelled`.
|