API reference › @evolu/common › Schedule › Schedule
type Schedule<Output, Input> = (
deps: ScheduleDeps,
) => (input: Input) => NextResult<readonly [Output, Millis]>;
Defined in: packages/common/src/Schedule.ts:111
Composable scheduling strategies for retry, repeat, rate limiting, and more.
A Schedule uses the State pattern: calling schedule(deps) creates a step
function with internal state captured in closures. Each call to step(input)
advances that state and returns Ok([Output, Millis]) or Err(Done<void>)
to stop. Multiple calls to schedule(deps) create independent state
instances.
Err(Done<void>) is terminal. After a step returns it, every subsequent call
to that step must also return Err(Done<void>).
With retry and repeat, the initial Task execution happens
before the first schedule step. Schedule outputs therefore describe
recurrences, not the initial execution. Time-based schedules establish their
time origin on the first step call, not when schedule(deps) creates the
step.
Composing a retry policy
import {
assertOk,
err,
exponential,
jitter,
maxDelay,
ok,
retry,
take,
testCreateRun,
type RandomNumber,
type Task,
} from "@evolu/common";
let attempts = 0;
const fetchData: Task<string, { readonly type: "FetchError" }> = () => {
attempts++;
return attempts < 2 ? err({ type: "FetchError" }) : ok("data");
};
const fetchWithRetry = retry(
fetchData,
// A jittered, capped, limited exponential backoff.
jitter("100%")(maxDelay("20s")(take(2)(exponential("100ms")))),
);
await using run = testCreateRun({
random: { next: () => 0 as RandomNumber },
});
assertOk(await run(fetchWithRetry), "data");
Or use a preset:
import {
assertTrue,
ok,
retry,
retryStrategyAws,
type Task,
} from "@evolu/common";
const fetchData: Task<string> = () => ok("data");
const fetchWithRetry = retry(fetchData, retryStrategyAws);
assertTrue(typeof fetchWithRetry === "function");