用 systemd timer 管理定时脚本:从首次运行到失败排查

10-01 4阅读

定时脚本最难维护的部分,通常不是时间表达式,而是“它以谁的身份运行、工作目录在哪里、失败后去哪里看”。在使用 systemd 的 Linux 主机上,可以让 service 描述工作,让 timer 描述触发时机。下面使用已经存在的 report 用户与脚本作为示例,安装前请替换路径并确认权限。

用 systemd timer 管理定时脚本:从首次运行到失败排查

AI生成概念配图:时钟触发服务,服务执行任务并留下检查记录,仅辅助理解,不代表真实界面或实测结果。

先让服务独立运行

创建 /etc/systemd/system/site-report.service。示例任务只读取业务数据并生成内部报告;脚本必须已安装、可执行,且 report 用户对目标目录有需要的权限。不要为了解决权限错误就让整项任务长期以 root 运行。

[Unit]
Description=Generate site report

[Service]
Type=oneshot
User=report
WorkingDirectory=/srv/site-report
ExecStart=/srv/site-report/run.sh
TimeoutStartSec=10min

这里的十分钟是演示超时,需要根据任务边界调整。ExecStart 不是交互式 shell 命令行,管道、重定向和 shell 展开不应直接照搬进去。复杂逻辑放进脚本,并为关键失败返回非零退出码。否则调度器看到“成功退出”,并不知道报表其实只写到一半。

再添加日历触发器

[Unit]
Description=Run site report daily

[Timer]
OnCalendar=*-*-* 02:30:00 UTC
Persistent=true
RandomizedDelaySec=5min

[Install]
WantedBy=timers.target

将以上内容保存为同名的 site-report.timer。未另外指定 Unit 时,它会触发对应的 service。示例明确使用 UTC,避免维护者误把服务器时区当成本地时区。RandomizedDelaySec 会引入随机延迟,所以此配置表达的是附近的时间窗口,不是精确到秒的业务承诺。

Persistent 对 OnCalendar 日历任务有意义:计时器重新激活时,若停用期间错过应触发的时间,会安排一次补跑。它不是逐条重放每个漏掉的日期。如果报表必须覆盖多天,脚本应保存处理水位,自己查找未完成的日期。这个设计能让补跑与手工重试走同一条可靠路径。

启用前做三层检查

sudo systemd-analyze verify \
  /etc/systemd/system/site-report.service \
  /etc/systemd/system/site-report.timer
systemd-analyze calendar '*-*-* 02:30:00 UTC'
sudo systemctl daemon-reload
sudo systemctl start site-report.service
sudo journalctl -u site-report.service --no-pager
sudo systemctl enable --now site-report.timer
systemctl list-timers --all site-report.timer

先检查语法与日历,再手动运行 service,确认产物无误后才启用 timer。这样能把“脚本问题”和“触发问题”分开。systemctl status 展示当前状态,journalctl 展示执行过程;还应查看输出文件时间、记录数量等业务证据,不能把 Active 一栏当作完整验收。

如果脚本依赖环境变量,不要假设服务会读取登录终端的配置。把必要参数通过经过审查的服务配置或配置文件明确提供,并限制敏感配置的读取权限。排错时只记录配置项是否存在,避免把密钥完整打印进 journal。

把重入与故障当成设计条件

同一 service 仍处于活动状态时,timer 不会为它再启动一个并行实例。但脚本如果自行转入后台、另有人工入口,仍可能产生重叠。让脚本保持前台执行,并按需要使用应用级互斥与幂等处理。不要为一次性任务随意加入 RemainAfterExit=yes,否则它可能保持活动状态,后续计时触发不会按预期再执行。

最后做一次受控失败演练:让测试任务返回错误,确认日志能定位原因、监控会发现产物缺失,再恢复配置。本文配置采用常见指令;发行版打包版本可能不同,具体行为应同时核对本机 man systemd.timer 和 systemd --version。

参考资料

文章版权声明:除非注明,否则均为云鹊BLOG原创文章,转载或复制请以超链接形式并注明出处。