A production-ready wrapper over node-cron with retries, overlap prevention, and timeout support.
npm install prod-cron-safenode-cron. Stop worrying about overlapping tasks, thundering herds, or hung processes. Prod-Cron-Safe adds the resilience and observability your production environment demands.
SIGINT and SIGTERM.
bash
npm install prod-cron-safe
`
---
🛠️ Basic Usage
`typescript
import { scheduleProdCron } from "prod-cron-safe";
const job = scheduleProdCron("/5 *", async () => {
// Your mission-critical code here
console.log("Daily cleanup started...");
}, {
name: "DailyCleanup",
preventOverlap: true,
retries: 3
});
job.start();
`
---
⚙️ Advanced Configuration (Options)
| Option | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| name | string | "unnamed-task" | Identification for logging and management. |
| preventOverlap | boolean | false | If true, skips execution if the task is already running. |
| executionTimeout| number | undefined | Timeout in ms. Kills the task if exceeded. |
| retries | number | 0 | Number of retry attempts on failure. |
| retryDelay | number | 1000 | Base delay in ms for retries. |
| maxRetryDelay | number | 30000 | Ceiling for exponential backoff (ms). |
| useExponentialBackoff | boolean | true | Enables exponential backoff (delay * 2^attempt). |
| jitter | boolean | true | Adds random noise to delay (prevents thundering herd). |
---
🪝 Lifecycle Hooks
Every hook receives a TaskContext containing the task ID, name, current attempt, and start time.
`typescript
scheduleProdCron("0 0 *", myTask, {
onStart: (ctx) => console.log([${ctx.name}] Started (Attempt ${ctx.attempt})),
onSuccess: (result, ctx) => {
console.log([${ctx.name}] Finished successfully in ${Date.now() - ctx.startTime.getTime()}ms);
},
onError: (err, ctx) => {
console.error([${ctx.name}] Failed after all retries: ${err.message});
},
onRetry: (err, attempt, delay, ctx) => {
console.warn([${ctx.name}] Retry ${attempt} in ${Math.round(delay)}ms due to: ${err.message});
}
});
`
---
📊 Management & Monitoring
$3
Access all registered tasks to monitor their state or history.
`typescript
import { getRegisteredTasks, stopAll } from "prod-cron-safe";
// get status of all tasks
const activeTasks = getRegisteredTasks();
activeTasks.forEach(task => {
console.log(${task.name} (${task.id}) - Running: ${task.isRunning});
console.table(task.history); // Last 20 executions
});
// kill everything gracefully
stopAll();
`
$3
Need to run a task right now? Use .trigger() without waiting for the cron schedule.
`typescript
const job = scheduleProdCron("0 0 *", cleanup);
await job.trigger(); // Runs manually, returns Promise with result
`
---
🛡️ Production Best Practices
$3
Prod-Cron-Safe automatically listens for SIGINT and SIGTERM to stop all jobs. This ensures your app exits cleanly without leaving dangling timers.
$3
Always return a Promise` from your task function. Rejections will trigger the retry logic automatically.