5 月 5 日发布的一篇技术文章主张,Linux 用户在新增定时任务时应优先考虑 systemd timers,而不是把所有周期脚本继续塞进 cron。文章给出的理由并不复杂:timers 能把调度、日志、状态和服务执行纳入同一套 systemd 工具链,排障成本更低。

这不是“cron 已死”的故事。cron 仍是 Unix 世界最耐用的基础工具之一,语法稳定、迁移容易、依赖少。但对今天维护服务器、桌面机、笔记本、自托管服务,或使用 Arch、NixOS 这类发行版的用户来说,定时任务早已不只是“几点跑脚本”,还包括失败追踪、环境隔离、错峰触发和休眠唤醒。

systemd timers 的定位:不是替脚本干活,而是替你管调度

systemd timer 本身不执行脚本,它通常调度同名的 .service。例如 backup.timer 默认触发 backup.service;如果要换目标,需要在 timer 里显式写 Unit=

项目cronsystemd timers判断
执行入口crontab 一行命令.timer 调度 .service结构更清楚,但文件更多
日志与状态常依赖邮件或脚本自处理journalctlsystemctl status排障优势明显
时间表达经典五段式OnCalendarOnBootSecOnUnitActiveSec相对时间是关键增量
集中触发需自行随机化RandomizedDelaySec 等内建更适合多机器场景

这里有一个容易踩坑的细节:systemctl start xxx.timer 只是启动计时器,不等于立刻运行服务。要立即执行任务,应启动对应的 .service。而 enable xxx.timer 才是让计时器随系统启动。

真正的差异在可观测性和执行语义

cron 的常见麻烦不是“不能跑”,而是“出事后不好查”。PATH 不同、标准输出被发到本机邮件、脚本环境和交互式 shell 不一致,都会让一次失败变成半小时翻日志。

systemd 也不是魔法。ExecStart= 默认不是普通 shell 行,管道不会自动按 shell 解释,环境变量也不会完整继承。要用管道、$RANDOM、复杂重定向或自定义 PATH,应显式调用 /usr/bin/env bash -c '...',或把逻辑写进脚本,并在 service 里使用绝对路径。这个限制反而是优点:它逼迫任务边界更明确。

时间表达也更贴近真实运维。固定日历时间用 OnCalendar=daily 或完整时间表达;“开机一小时后执行,再每小时执行”则更适合 OnBootSec=1hOnUnitActiveSec=1h。写完后用 systemd-analyze calendar 校验,用 systemctl list-timers 看下一次、上一次和剩余时间,这是 timers 比 crontab 更像运维工具的地方。

错峰、唤醒和限制,决定它能不能当默认方案

在多台机器同时检查更新、备份或请求 API 时,集中触发会制造 thundering herd。systemd 提供 RandomizedDelaySecFixedRandomDelayRandomizedOffsetSec,可把任务稳定地摊开,减少同一秒内集体开跑。对自托管用户,这可能意味着备份、同步、证书续期不再挤在午夜。

还有一个桌面用户会关心的能力:WakeSystem= 可在硬件支持时唤醒休眠系统执行任务。比如夜间预取 Arch 或 NixOS 的更新包,早上再手动升级。但服务跑完后是否重新休眠,需要另行处理,timer 不会替用户完成整套电源策略。

接下来最该观察的不是 cron 会不会消失,而是团队是否愿意把定时任务纳入 systemd unit 管理。小型脚本继续用 cron 没问题;新建的备份、清理、更新、轮询任务,如果已经运行在 systemd 系统上,timers 更适合做默认起点。