@cch137/every
v0.1.0
Published
Zero-dependency, wall-clock-aligned interval scheduler — every("5m", fn).
Downloads
84
Maintainers
Readme
@cch137/every
Zero-dependency, wall-clock-aligned interval scheduler. One verb — every —
schedules recurring work on clock boundaries (:00, :05, :10, …) instead of
relative to when you subscribed. A single timer sleeps until the next boundary
(no per-second polling) and re-arms from Date.now() each tick, so it
self-corrects for drift. Runs on Node ≥ 20, Deno, and edge runtimes.
See DESIGN.md for goals, non-goals, and engine details.
Install
npm i @cch137/everyimport { every, everyMinute, createClock } from "@cch137/every";
// Deno: import { every } from "npm:@cch137/every";Usage
import { every, everySecond, everyMinute, everyHour, everyDay } from "@cch137/every";
// Generic — interval as a duration string, ms number, or { minutes: 5 }.
const stop = every("5m", () => syncStuff());
stop(); // unsubscribe
// Named shortcuts for the common units.
everyMinute((tick) => console.log(tick.seq, tick.t));
// Options: dispatch mode, overlap guard, error handling, alignment.
every("10s", doWork, {
preventOverlap: true, // skip if the previous async run is still going
onError: (err) => log.warn(err), // isolate handler errors
});interval accepts 500ms / 30s / 5m / 2h / 1d / 1h30m, a number of
milliseconds, or { days, hours, minutes, seconds, ms }.
Isolated clocks
The top-level helpers are bound to a shared default clock. For tests, multiple independent schedules, or to wire in latency reporting, create your own:
import { createClock } from "@cch137/every";
const clock = createClock({
onLatency: (info) => log.warn(`clock late by ${info.lateBy}ms`),
});
clock.every("2h", purge);
clock.everyDay(rollup); // aligned to UTC midnight
clock.stop(); // pause; subscriptions resume on start()createClock uses autoStart by default: the first subscription starts the
timer, the last to leave stops it, so an idle clock keeps no timer and never
holds the process open on its own.
Behavior
- Alignment — default
align: "wall"fires on epoch multiples of the interval.align: "relative"behaves likesetInterval(interval from registration).everyDay/"1d"align to UTC midnight. - Coalescing — if the loop is delayed past several boundaries (sleep, blocked event loop), each subscription fires once and re-anchors; missed boundaries are not replayed.
- Latency — pass
onLatencytocreateClockto observe late wake-ups (default threshold 1500ms).
License
MIT
