Cron is a clock, not a supervisor. It checks the time, sees a match, and starts your job. It never asks whether the last run finished.
Most of the time that's fine. Then one day a job runs long, the next one starts on schedule anyway, and now two copies are writing to the same table.
Reading a cron expression without a cheat sheet
Unix cron uses five fields, left to right:
* * * * *
| | | | |
| | | | day of week (0-6, Sunday is 0)
| | | month (1-12)
| | day of month (1-31)
| hour (0-23)
minute (0-59)
A job should run at 10 PM on weekdays? That's:
0 22 * * 1-5
Read it as: minute 0, hour 22, any day of the month, any month, Monday through Friday. The * just means "no restriction on this field."
Note the pattern is about wall-clock time only. Cron fires when the time matches, whether or not anything else is still running. That's what makes it good for things like overnight batch jobs or a report that must go out at exactly 9 AM. It's also what makes overlap possible.
The overlap problem
Say a job is scheduled hourly, but a heavy day pushes it to 70 minutes. At the top of the next hour the clock matches again, and a second run starts while the first is still going. Two runs now compete for the same rows, the same API quota, the same CPU.
You can fix this by hand with lock files or a "is another run active" check at the top of every script. It works until someone forgets to add it to the next job.
The cleaner option is to make it a property of the schedule. In Unmeshed, that's a single setting: "Do not allow overlap." If the previous run is still going when the next slot arrives, the new run doesn't start. One instance at a time, no lock logic in your code.
What else is worth setting on a schedule
A few settings that save trouble later:
- Time zone. A 10 PM job means very different things in two regions, so pick it explicitly.
- Start time. Run immediately, or begin at a future date.
- On/off toggle. Pause a schedule without deleting it.
And once it's live, you want somewhere to see upcoming runs and past executions, so "did the nightly job run?" is a lookup instead of a guess.
So, which one do you need?
If a job must fire at a precise time and each run is quick, plain cron is enough. If runs can stretch past the interval, or the job touches shared data, turn on the overlap guard before the first long run teaches you why.
Everything above is how scheduling works in Unmeshed, where cron expressions, overlap control, and run history sit in the same Schedules tab.
Top comments (0)