Cron and timer units run commands without a terminal, without your login profile, and usually with a minimal PATH. Scripts that call tools by short name, rely on shell aliases, or assume a current directory fail there, often silently, because nobody is watching stdout.
Make scheduled work observable and safe:
- Reproduce in the job's environment.
env -i HOME=/tmp PATH=/usr/bin:/bin bash script.shis closer to cron than your shell is. - Log success and outcome, not just start. "cleanup: removed 0 markers" every hour for weeks is data. Alert on it.
- Be idempotent. Jobs get retried, run twice after clock changes, or overlap when a run is slow. Writing a report with
>instead of>>, or using a lock, keeps reruns harmless. - Bound runtime. A job that can run longer than its interval will pile up. Timers skip a start while the previous run is active. Cron does not.
The SRE book's cron chapter adds the distributed view. At scale, "run exactly once per interval" is a consensus problem, and it is often better to design jobs that tolerate being skipped or doubled than to promise either never happens.