`noOverlap` blocks new runs even after async task finishes
Summary
When using noOverlap: true with an async task, node-cron continues to log that the task is still running and keeps blocking new executions, even though the async function has already finished and my own code logs an exit message.
Code
import { schedule as cronSchedule } from 'node-cron';
const scheduledTask = cronSchedule(
appConfig.cron!.expression,
async () => {
const { error } = await tryCatch(startJob());
if (error) {
logger.error({ msg: 'Error during job', error, failurePenaltySeconds });
await delay(failurePenaltySeconds);
}
console.log('finished async function');
},
{
noOverlap: true,
}
);
Cron expression: */10 * * * * *
Logs
{"level":"info","time":1765385331754,"pid":18,"msg":"exiting safely","exitCode":0}
finished async function
[2025-12-10T16:49:00.010Z] [PID: 18] [NODE-CRON] [WARN] task still running, new execution blocked by overlap prevention!
[2025-12-10T16:49:10.001Z] [PID: 18] [NODE-CRON] [WARN] task still running, new execution blocked by overlap prevention!
[2025-12-10T16:49:20.002Z] [PID: 18] [NODE-CRON] [WARN] task still running, new execution blocked by overlap prevention!
...
[2025-12-10T16:50:50.003Z] [PID: 18] [NODE-CRON] [WARN] task still running, new execution blocked by overlap prevention!
The JSON log
{"level":"info","time":1765385331754,"pid":18,"msg":"exiting safely","exitCode":0}
is emitted from inside startJob(). After that, my code logs finished async function, so from my side the Promise chain has completed.
However, node-cron still thinks the task is running and continues to block future executions because of noOverlap.
Questions / debugging attempts
I’m currently not sure how to debug this further. A few questions:
- Is there any known limitation or caveat with
noOverlapand async functions (or Promises) that I might be missing? - Does
node-cronexpect a specific pattern (e.g. returning the Promise explicitly instead of usingasync/await), or any other configuration fornoOverlapto work correctly with async tasks? - Is there any way to introspect / reset the internal state that tracks whether a task is “still running”?
If there’s anything obvious I’m doing wrong, I’d really appreciate pointers. I’m also happy to try out any debugging steps or extra logging if that would help.
Environment
node-cronversion: 4.1.0- Node.js version v20.19.0
- OS: Debian GNU/Linux 12 (bookworm)
- Runtime context: Docker container (
node:20.19.0-slimas base image)