Skip to content

Running tick

Rungs has no background thread. Deadlines, reminders, escalations, timeouts and the reminders of blocked steps are applied when you call rungs.tick(), at the time your clock returns. Run it on a schedule:

// One loop in a worker process: apply what is due, then deliver events. Several workers may run
// at once; with the PostgreSQL store they claim different requests (EC-27).
export function startWorker(rungs: Rungs, everyMs = 60_000): () => void {
let running = false;
const run = async () => {
if (running) return; // never overlap with a slow previous run
running = true;
try {
const { failed } = await rungs.tick({ limit: 500 });
for (const { requestId, error } of failed) console.error("tick failed", requestId, error);
await rungs.dispatchPending({ limit: 500 });
} catch (error) {
console.error("worker run failed", error); // the next run tries again
} finally {
running = false;
}
};
const timer = setInterval(run, everyMs);
void run();
return () => clearInterval(timer);
}

Runs in CI:examples/docs-snippets/src/guides/tick.ts

  • How often: every minute is plenty for deadlines measured in hours or days.
  • Several workers: safe. Each due action is applied once, and the PostgreSQL store hands different requests to different workers (EC-27).
  • Missed runs: a late tick catches up with one reminder, not one per missed interval.
  • Failures: one failing request does not stop the others; it is reported in failed and tried again next time.

On serverless platforms, call the same two functions from a scheduled function or cron route instead of setInterval.