家里的小机器上有几件每天做一次的杂事:清点目录大小、整理索引、检查备份结果。以前我只在日历里记时间,失败了再去翻终端历史。后来把这些任务迁到 timer,最大的改善是每个任务都有一个名字,执行状态和日志也能放在一起查。这里用每天统计文档目录大小演示,不涉及删除或修改原文件。
先把任务单独跑通
timer 负责触发,service 负责执行。先确认机器上已有普通账户 ay,并且它能读取 /home/ay/Documents;换到自己的机器时,这两个位置都要按实际情况调整。下面的服务使用绝对路径,不依赖登录终端里的别名和环境变量。
[Unit]
Description=Measure the documents directory
[Service]
Type=oneshot
User=ay
ExecStart=/usr/bin/du --summarize --block-size=1 /home/ay/Documents
StandardOutput=journal
StandardError=journal
Nice=10
TimeoutStartSec=10min
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=read-only
Type=oneshot 适合运行完就退出的命令。这里没有设置 RemainAfterExit,否则成功后服务仍处于活动状态,后面的定时触发就可能没有新的执行。只读限制适合这个清点任务;若换成需要写文件的任务,要重新考虑写入目录和权限,不能照抄限制项。
我会先手动启动一次。命令退出后显示 inactive 并不等于失败,短任务执行结束本来就不需要常驻。真正要看的是退出状态以及日志内容。服务文件里的命令也不会自动经过 shell,管道、重定向和多条命令应放进单独的脚本,再由服务调用。
再决定什么时候执行
[Unit]
Description=Daily documents size check
[Timer]
OnCalendar=*-*-* 03:20:00
Persistent=true
RandomizedDelaySec=10m
AccuracySec=1m
Unit=document-size.service
[Install]
WantedBy=timers.target
这个表达式使用机器当前的本地时区。机器搬家或改过时区后,我会重新确认下一次触发时间,不凭印象推算。随机延迟让任务分散在一个时间窗口里,因此它不承诺三点二十分整开始;精度窗口也可能带来合并唤醒的延迟。对这份日报,这种偏差完全可以接受。
如果任务要求从上一次结束后再隔一段时间执行,可以考虑基于单调时钟的定时方式,例如 OnUnitInactiveSec。它和日历表达式的语义不同,不应该只换一个字段就认为行为相同。这里的需求是每天一次,所以保留日历方式。
启用与检查
sudo systemd-analyze verify /etc/systemd/system/document-size.service /etc/systemd/system/document-size.timer
systemd-analyze calendar '*-*-* 03:20:00'
sudo systemctl daemon-reload
sudo systemctl start document-size.service
sudo journalctl -u document-size.service -n 30 --no-pager
sudo systemctl enable --now document-size.timer
systemctl list-timers --all document-size.timer
systemctl show document-size.service -p Result -p ExecMainStatus
先验证语法,再验证实际执行,最后启用 timer。这里启用的是定时器,服务本身不需要设置开机常驻。修改 unit 文件后要重新载入配置;如果修改了触发规则,我还会重启定时器,并查看列表里的下一次时间。列表给出的结果比只读配置文件更能说明当前生效的状态。
补跑的边界
Persistent=true 对日历定时器有用:机器关机错过计划后,定时器再次激活时,可以补触发一次。它不会为停机期间的每一天逐次重放任务,随机延迟也仍可能生效。依赖每天一份输出的脚本,需要自己决定缺失日期怎样补齐。
同一个服务还在运行时,timer 不会再为它启动一份并行实例。因此长任务可能跳过某些计划时刻,而不是排出一串队列。我给清点设置了超时,也让真正的维护脚本能重复执行且结果一致。定时器解决的是触发和可观察性,任务本身的边界仍要自己设计。
这份记录针对使用 systemd 的 Linux 主机。运行前先查看本机手册,确认可执行文件位置、账户和目录;不要为了让配置通过而把整个任务改成最高权限运行。