用 systemd timer 替代 cron:日历、补跑和抖动

举报
yd_240066378 发表于 2026/10/26 06:11:08 2026/10/26
【摘要】 很多机器上还留着一行 crontab。它能跑,但失败时往往只剩一封没人看的邮件,或者什么都没有。systemd timer 把「什么时候触发」和「真正执行什么」拆成两个单元,触发记录进 journal,错过的时间点还可以补跑。这篇只讲用户级 timer 的最小可用写法,不改系统服务,也不讨论定时表达式的全部语法。先准备一个只做一件事的 service。假设每天整理一次家目录临时文件夹里超过七...

很多机器上还留着一行 crontab。它能跑,但失败时往往只剩一封没人看的邮件,或者什么都没有。systemd timer 把「什么时候触发」和「真正执行什么」拆成两个单元,触发记录进 journal,错过的时间点还可以补跑。这篇只讲用户级 timer 的最小可用写法,不改系统服务,也不讨论定时表达式的全部语法。





先准备一个只做一件事的 service。假设每天整理一次家目录临时文件夹里超过七天的普通文件,把定义写到 ~/.config/systemd/user/tidy-tmp.service:





[Unit]


Description=Remove stale files under tmp





[Service]


Type=oneshot


ExecStart=/usr/bin/find %h/tmp -type f -mtime +7 -delete





Type=oneshot 表示进程结束单元就结束,timer 不会把它当成常驻服务反复拉起。%h 是 systemd 的家目录说明符,比在单元里写死 /home/某人 更不容易在换账号时踩坑。命令用绝对路径,避免用户环境和非登录 shell 的 PATH 不一致。





再写同目录下的 tidy-tmp.timer:





[Unit]


Description=Daily tidy of tmp





[Timer]


OnCalendar=*-*-* 03:20:00


Persistent=true


RandomizedDelaySec=15min





[Install]


WantedBy=timers.target





OnCalendar 是日历事件,不是「每隔多久」。上面这行表示每天 03:20。机器当时如果关机,Persistent=true 会在下次启动后尽快补跑一次,而不是把这一轮静默丢掉。RandomizedDelaySec 把实际启动时间在十五分钟内错开,避免同一台机器上的多个任务挤在整点。目的和在 cron 里写 sleep 随机数一样,但延迟写在单元里,systemctl cat 就能看到,不用再去读脚本。





启用只针对当前用户:





systemctl --user daemon-reload


systemctl --user enable --now tidy-tmp.timer


systemctl --user list-timers





list-timers 会列出 NEXT 和 LAST。刚启用时 LAST 是空的,只说明还没跑过,不要据此判断单元损坏。想先验证命令,可以 systemctl --user start tidy-tmp.service,再用 journalctl --user -u tidy-tmp.service -n 50 看退出码。timer 激活和服务成功是两件事:timer 到点只负责拉起服务,服务返回非零要到 service 自己的日志里查。





和 cron 相比,有三处容易误判。第一,用户级 timer 默认跟着用户会话,图形界面退出后可能停止。如果希望开机后、尚未登录时也跑,对该用户执行 loginctl enable-linger,而不是急着把单元改成系统级。第二,改完文件必须 daemon-reload,否则内存里仍是旧定义,enable 看起来成功,行为却没变。第三,日历写错时,用 systemd-analyze calendar '*-*-* 03:20:00' 可以直接展开接下来几次触发点,比把 crontab 留到明天碰运气更快。





不建议一次把全部 cron 迁完。先选一个可重入、失败了也没有副作用的任务,连续两天核对 list-timers 的 LAST 和 journal 里的退出码,再决定其余条目要不要换。timer 带来的是可观察性和补跑,不是把调度本身变复杂。


还有一个容易和 cron 混淆的地方。OnUnitActiveSec 是单调计时,从上一次服务被激活开始再等一段间隔,适合「跑完再隔一小时」。OnCalendar 对齐的是墙上时钟。清理临时文件更适合后者,因为你关心的是每天固定窗口,而不是上次结束后再等二十四小时。服务如果偶尔多跑十分钟,单调间隔会把触发点一天天往后挪。


timer 和 service 应放在同一目录,并使用相同的主文件名,systemd 才会把它们配成一对。主文件名不一致时,要在 timer 里用 Unit= 显式指向,否则 list-timers 看得到触发,journal 里却是找不到单元。核对时优先看 systemctl --user status tidy-tmp.timer,确认 Loaded、Active 和 Trigger 三行,而不是只看 enable 命令有没有报错。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。