用 systemd timer 替代 crontab:迁移时最容易踩的五个点
用 systemd timer 替代 crontab:迁移时最容易踩的五个点
crontab -e 写一行就够了,为什么还要换成 systemd timer?因为 cron 有几个说不清的地方:任务失败没有记录、并发跑会叠在一起、机器关机错过的任务不会补、环境变量跟你登录 shell 完全不是一回事。systemd timer 把这些都变成了显式配置项。
但迁移过程里有五个细节,不注意会踩。
一、cron 的时间字段要换算
cron 的 30 8 * * * 在 timer 里是:
[Timer]
OnCalendar=*-*-* 08:30:00
Persistent=true
OnCalendar 的格式是 星期 年-月-日 时:分:秒,日常只用 *-*-* HH:MM:SS。想每 15 分钟跑一次,别写 *:0/15,要写 *:0/15:00——秒位不能省,否则解析失败。
验证表达式对不对,不用等时间到:
systemd-analyze calendar '*-*-* 08:30:00'
systemd-analyze calendar '*:0/15:00'
输出会给出下次触发时间,比猜可靠。
二、Persistent=true 是 cron 没有的能力
关机期间错过的任务,systemd 会在开机后补跑一次。这对每日备份、证书续期这类任务很关键。
要注意它只补一次,不会把错过的十次全补上。也不需要额外装 anacron。
三、环境变量不是你的 shell
cron 的经典坑是 PATH 只有 /usr/bin:/bin,systemd 更严格:默认几乎没有环境变量,HOME 可能都没有。
两个办法:
[Service]
Environment=PATH=/usr/local/bin:/usr/bin:/bin
Environment=HOME=/root
或者用一个 wrapper 脚本,在脚本里 source 环境文件。后者更好维护,尤其是需要读 .env 的场景。
调试时先跑一次手动触发,看环境对不对:
systemctl start mytask.service
journalctl -u mytask.service -n 50 --no-pager
四、Type=oneshot 与 RemainAfterExit
定时任务通常是 Type=oneshot:进程退出即结束,systemd 记录退出码。
如果你希望「跑完之后状态保持 active」,加 RemainAfterExit=yes。但对备份这类任务没必要,反而会让 systemctl status 显示得像是常驻服务。
失败重试不要用 Restart=always——oneshot 配合 always 会在失败后立刻无限重启。要重试就显式写:
Restart=on-failure
RestartSec=5min
StartLimitBurst=3
五、别把 timer 和 service 写成同一个文件
一个 timer 对应一个同名 service:
backup.timer负责什么时候跑backup.service负责跑什么
启用的是 timer,不是 service:
systemctl enable --now backup.timer
systemctl list-timers --all
只 enable service 不会定时执行,这是迁移里最常见的「配了但不跑」。
一个完整的例子
# /etc/systemd/system/backup.service
[Unit]
Description=Daily backup
After=network-online.target
[Service]
Type=oneshot
User=root
Environment=PATH=/usr/local/bin:/usr/bin:/bin
ExecStart=/usr/local/bin/backup.sh
Nice=10
IOSchedulingClass=idle
[Install]
WantedBy=multi-user.target
# /etc/systemd/system/backup.timer
[Unit]
Description=Run backup daily at 03:20
[Timer]
OnCalendar=*-*-* 03:20:00
Persistent=true
RandomizedDelaySec=300
[Install]
WantedBy=timers.target
RandomizedDelaySec 是另一个 cron 没有的好处:多台机器同一时间跑备份时,随机错开最多 5 分钟,避免同时打满存储。
什么时候不该换
如果任务很短、机器单一、你不关心失败记录,cron 完全够用。systemd timer 的价值在可观测性和可靠性:journalctl 能查每次运行的输出和退出码,systemctl list-timers 能看到下次和上次触发时间。
迁移的收益不是「更现代」,而是出问题时你能说清楚发生了什么。
- 点赞
- 收藏
- 关注作者
评论(0)