cron 式语法并不是维护任务契约的全部。命令需要一个清晰的服务身份、一个有界的运行时间,以及能区分"未调度"与"运行但失败"的证据。一个 systemd 定时器与 oneshot 服务能把这些关注点分开。
把工作定义成服务
使用显式用户与绝对命令路径:
# /etc/systemd/system/site-check.service
[Unit]
Description=Read-only public site check
[Service]
Type=oneshot
User=sitecheck
ExecStart=/usr/local/bin/check-public-site
TimeoutStartSec=2min
TimeoutStartSec 防止网络或子进程等待无限占用调度。当契约失败时,helper 应返回非零退出码,并且不得修改它所检查的服务。
调度该服务
# /etc/systemd/system/site-check.timer
[Unit]
Description=每小时运行公共站点检查
[Timer]
OnCalendar=hourly
Persistent=true
RandomizedDelaySec=5min
Unit=site-check.service
[Install]
WantedBy=timers.target
Persistent=true 会在机器恢复后补跑错过的日历事件。RandomizedDelaySec 把一个窗口内的例行工作分散开;当任务必须在精确时刻运行时它并不合适。
启用前先验证
检视日历表达式,然后手动启动服务:
systemd-analyze calendar hourly
systemctl start site-check.service
systemctl status site-check.service
journalctl -u site-check.service -n 50 --no-pager
只有当服务在预期的用户、环境、路径与网络访问下成功时才启用定时器:
systemctl enable --now site-check.timer
systemctl list-timers site-check.timer
对服务结果告警
定时器触发并不等于成功。要监控 oneshot 服务的退出状态或日志结果。保持 stdout 简洁,调试需要的详细制品写入一个有界的路径。
来源
- systemd.timer(5),日历定时器、持久化与延迟行为,已核验 2026-08-23。
- systemd.time(7),日历表达式语法,已核验 2026-08-23。
- systemd.service,oneshot 服务语义,已核验 2026-08-23。