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 简洁,调试需要的详细制品写入一个有界的路径。

来源