@helipod/scheduler 0.1.0 → 0.1.2
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 +62 -0
- package/package.json +8 -8
package/README.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# @helipod/scheduler
|
|
2
|
+
|
|
3
|
+
Durable scheduled functions for helipod: run a mutation or action later, at an exact time, or on a recurring cron cadence — stored as rows in your database, dispatched by a background driver that survives restarts.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
bun add @helipod/scheduler
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Enable
|
|
12
|
+
|
|
13
|
+
Components are opt-in per project. Compose the scheduler in `helipod.config.ts`:
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
// helipod.config.ts
|
|
17
|
+
import { defineConfig } from "@helipod/component";
|
|
18
|
+
import { defineScheduler } from "@helipod/scheduler";
|
|
19
|
+
|
|
20
|
+
export default defineConfig({
|
|
21
|
+
components: [defineScheduler()],
|
|
22
|
+
});
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
To add recurring jobs, declare them with `cronJobs()` (typically in `helipod/crons.ts`) and pass the registry via `defineScheduler({ crons })`:
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
const crons = cronJobs();
|
|
29
|
+
crons.interval("cleanup", { minutes: 5 }, "maintenance:_purge", {});
|
|
30
|
+
crons.cron("nightly", "0 3 * * *", "reports:_build", {}, { tz: "America/New_York" });
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Usage
|
|
34
|
+
|
|
35
|
+
Once composed, `ctx.scheduler` is available in every mutation (and, via a delegating facade, every action):
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
export const notifyLater = mutation({
|
|
39
|
+
handler: async (ctx, { userId }) => {
|
|
40
|
+
const jobId = await ctx.scheduler.runAfter(60_000, "reminders:_send", { userId });
|
|
41
|
+
// or: await ctx.scheduler.runAt(new Date("2026-08-01T09:00:00Z"), "reminders:_send", { userId });
|
|
42
|
+
// later: await ctx.scheduler.cancel(jobId);
|
|
43
|
+
return jobId;
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Features
|
|
49
|
+
|
|
50
|
+
- `ctx.scheduler.runAfter(delayMs, fnRef, args)` and `runAt(ts, fnRef, args)` — schedule a mutation or action; the job row is written in the calling mutation's own transaction, so the schedule commits or rolls back atomically with your write.
|
|
51
|
+
- `ctx.scheduler.cancel(id)` — cancel a pending job, with cascading cancel of child jobs.
|
|
52
|
+
- `cronJobs()` recurring schedules: `.interval()`, `.cron()` (with time zones), `.daily()`, `.hourly()`, `.weekly()`, `.monthly()`, reconciled into the `crons` table at boot, with configurable catch-up policies for missed occurrences.
|
|
53
|
+
- Retries with exponential backoff; mutations default to 4 attempts, actions to 1 (at-most-once unless you opt in via `retry: { maxFailures }`). Crash-looping jobs are dead-lettered, not re-dispatched forever.
|
|
54
|
+
- Lower-level `enqueue(fnRef, args, opts)` with `idempotencyKey`, `onComplete` callbacks, and an opaque `context` value round-tripped to the callback — the primitive other components build on.
|
|
55
|
+
- A reactive driver: dispatch wakes on every commit plus a wall-clock timer armed to the earliest pending job. No polling loops, no lost work across restarts.
|
|
56
|
+
- Jobs are ordinary rows (`scheduler/jobs`, `scheduler/crons`) — browsable in the dashboard like any other table.
|
|
57
|
+
|
|
58
|
+
No dependencies on other components; it is the base layer `@helipod/workflow`, `@helipod/triggers`, and `@helipod/notifications` build on.
|
|
59
|
+
|
|
60
|
+
Part of [Helipod](https://github.com/helipod-sh/helipod) — docs at https://helipod-six.vercel.app/docs
|
|
61
|
+
|
|
62
|
+
License: FSL-1.1-Apache-2.0
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@helipod/scheduler",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"license": "FSL-1.1-Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -17,16 +17,16 @@
|
|
|
17
17
|
"test": "vitest run"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@helipod/component": "0.1.
|
|
21
|
-
"@helipod/errors": "0.1.
|
|
22
|
-
"@helipod/executor": "0.1.
|
|
23
|
-
"@helipod/values": "0.1.
|
|
20
|
+
"@helipod/component": "0.1.2",
|
|
21
|
+
"@helipod/errors": "0.1.2",
|
|
22
|
+
"@helipod/executor": "0.1.2",
|
|
23
|
+
"@helipod/values": "0.1.2",
|
|
24
24
|
"cron-parser": "^4.9.0"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@helipod/client": "0.1.
|
|
28
|
-
"@helipod/docstore-sqlite": "0.1.
|
|
29
|
-
"@helipod/runtime-embedded": "0.1.
|
|
27
|
+
"@helipod/client": "0.1.2",
|
|
28
|
+
"@helipod/docstore-sqlite": "0.1.2",
|
|
29
|
+
"@helipod/runtime-embedded": "0.1.2",
|
|
30
30
|
"@types/node": "^22.10.5",
|
|
31
31
|
"tsup": "^8.3.5",
|
|
32
32
|
"typescript": "^5.7.2",
|