UNPKG

non-overlapping-periodic-job-scheduler

Version:

Periodic job scheduler for Node.js projects, ensuring non-overlapping executions and deterministic termination. Features a dynamically chosen interval between executions, determined by a user-injected calculator function, which can take into account the d

51 lines (48 loc) 2.96 kB
export type PeriodicJob = () => Promise<void>; export const NO_PREVIOUS_EXECUTION = -1; /** * CalculateDelayTillNextExecution * * Dynamically sets the delay between consecutive executions. This function is invoked immediately * after the ith execution finishes, determining the delay until the (i+1)th execution starts. * * The determined delay is the interval between the end of the ith execution and the start of the * (i+1)th execution. The user is provided with two parameters to aid in this decision: * - `justFinishedExecutionDurationMs`: The duration of the just-finished execution in milliseconds. * - `justFinishedExecutionError`: The error thrown by the just-finished execution, if any. * * Both arguments are optional, even though the scheduler **always provides** the first argument. * This design enables users to ignore the `justFinishedExecutionDurationMs` argument when it is * irrelevant, while preventing potential TypeScript or linting errors caused by unused arguments. * * ## Base Case * The first invocation is triggered by the `start` method, using `NO_PREVIOUS_EXECUTION` as the * pseudo previous-execution-duration. In this scenario, the user determines the first delay without * prior execution data. * For example, the user may want the first execution to occur immediately after `start` (0ms delay). * * ## With Great Power comes Great Responsibility * This function should never throw. If it does, scheduling will stop. * * ## Example Interval Policy * For example, the user may prefer a longer interval between successful executions and a shorter * interval after a failed attempt (indicated by an error). The scheduler does not consider other * complex factors, which the user may choose to include (e.g., time of day, peak hours). * The calculation callback can capture any data structures or information to help the user make * an informed decision. * * ## Mimicking the `setInterval` Policy * It is possible to mimic the `setInterval` behavior, ensuring a fixed interval between *start* timestamps. * For example, if a 5000ms interval between consecutive starts is desired and the current execution took * 1000ms, the next execution delay would be 5000ms - 1000ms = 4000ms. * However, be aware that actual execution time might exceed the fixed interval. In such cases, you need to * choose a suitable delay that makes sense for your use case. A plausible approach is to set the next * execution delay to 0ms. Another approach could be scheduling the next execution to the next 5000ms * interval from the start, i.e., 5000 - (justFinishedExecutionDurationMs % 5000). * This flexibility in delegating the decision-making to users makes this component well-suited for a * variety of use cases. */ export type CalculateDelayTillNextExecution<JobError = Error> = ( justFinishedExecutionDurationMs?: number, justFinishedExecutionError?: JobError ) => number;