Cron job timeout: kill a hung run before it overlaps
A cron job with no timeout can hang indefinitely — waiting on a network call, a lock, or a stuck process — and if it runs long enough it overlaps the next scheduled run, stacking up duplicate processes. Wrap the job in the `timeout` command so a run that exceeds a limit is killed automatically. A job killed by timeout exits with a signal code (124 for the timeout itself, or 137 if it had to escalate to SIGKILL), which withholds the success ping and lets a monitor alert you that the run hung.
Why does a hung cron job cause overlapping runs?
cron starts a new run every time the schedule fires, regardless of whether the previous run finished. If a nightly job normally takes 10 minutes but one night hangs for hours, the next night's run starts on top of it — and now two copies are competing for the same database rows, files, or locks. Left unchecked, a hang can pile up many overlapping processes.
How do I add a timeout to a cron job?
Wrap the command in the coreutils `timeout` command. It runs the command and kills it if it exceeds the given duration:
# timeout sends SIGTERM after 30m; --kill-after escalates to SIGKILL if the
# job ignores TERM for another 30s. Exit 124 = the timeout fired.
0 3 * * * timeout --kill-after=30s 30m /usr/local/bin/nightly.shTo also prevent overlap when a run legitimately runs long, take a lock with `flock` so a second run can't start while the first holds it:
0 3 * * * flock -n /tmp/nightly.lock timeout 30m /usr/local/bin/nightly.shWhat exit code does a timed-out job return?
The `timeout` command exits 124 when the time limit was reached and the command was killed. If you used --kill-after and it had to send SIGKILL, the exit reflects that signal (137 = 128 + 9). Either way it is non-zero, so a success-only ping is withheld and the monitor treats the run as failed.
How do I get alerted when a job hangs?
Ping the monitor only on a clean completion, so a run killed by timeout sends nothing and alerts as a miss:
0 3 * * * timeout 30m /usr/local/bin/nightly.sh && curl -fsS -m 10 --retry 3 "https://ping.cronshield.com/<your-check-id>"Catch this failure automatically
The free tier gives you a heartbeat endpoint and an email alert when an expected ping doesn't arrive. Paid tiers add the log-aware diagnosis — the last log line and a likely cause in the alert. The heartbeat receiver ships in an upcoming release; see the plans to learn what each tier adds.
Frequently asked questions
- What exit code does the timeout command return?
- The coreutils `timeout` command exits 124 when the command runs past the limit and is killed. With --kill-after, if it escalates to SIGKILL the status reflects the signal instead (137). Both are non-zero, so a success-only heartbeat is correctly withheld.
- How do I stop cron jobs from overlapping?
- Wrap the command in `flock -n <lockfile>` so a second run can't acquire the lock while the first still holds it, and add a `timeout` so a hung run is eventually killed and the lock released. Together they prevent both indefinite hangs and stacked duplicate runs.
Primary sources
- GNU coreutils manual — timeout exits 124 on timeout; --kill-after / --signal — verified 2026-07-04
- man flock(1) — mutual-exclusion lock to prevent overlapping runs — verified 2026-07-04