定时任务的六个可靠性习惯:Persistent、flock 与结构化结果

举报
yd_269248920 发表于 2026/11/13 00:34:27 2026/11/13
【摘要】 把脚本挂成每日定时任务很容易,难的是连续几个月不出错。这篇记录六条固定习惯:timer 的 Persistent 与抖动、flock -n 互斥、control-group 超时收尾、日志交给 journald、结果落结构化 JSON、开工前环境断言。

背景

把一个脚本挂成每日定时任务很容易,难的是让它连续几个月不出错:机器重启错过执行点、任务跑超时后上一轮还没结束就开了下一轮、日志无限膨胀把根分区写满。这三件事我都遇到过,最后用 systemd timer + flock + 一个小而固定的日志策略解决。

一、timer 的 Persistent 要打开

systemd timer 默认是「按墙钟触发」,机器关机的那段时间直接跳过。加一行 Persistent=true,systemd 会记录上次触发时间,开机后如果发现错过了,会立刻补跑一次。对签到、拉报表这类「补跑有意义」的任务,这一行是刚需。

[Timer]
OnCalendar=*-*-* 00:30:00
Persistent=true
RandomizedDelaySec=300

顺手加个 RandomizedDelaySec:同一批机器都盯着 00:30,不加抖动的话会在整点把上游接口打出一小波峰值。

二、flock 放在 ExecStart 里,不要放脚本里

很多人习惯在脚本开头自己写 pid 文件判断,但异常退出留下的 stale pid 会让后续每一次执行都被自己挡住。systemd 场景下更省事的做法是把互斥交给 flock:

ExecStart=/usr/bin/flock -n /run/myjob.lock /usr/local/bin/myjob.sh

-n 是关键,表示拿不到锁就立刻失败退出,而不是排队。排队会带来一个更隐蔽的问题:任务迟到几小时后突然集体开跑,行为和你白天调试时完全不同。让它在日志里明确写一条「locked, skip」比排队安全得多。

配对地,unit 里最好加上:

[Service]
Type=oneshot
TimeoutStartSec=1800
KillMode=control-group

KillMode=control-group 保证超时后连子进程一起收掉,否则留下的孤儿进程会继续占着锁和端口,下一轮又会因为「锁被占」静默跳过,形成「日志里天天说跳过、实际什么都没做」的假象。

三、日志:让 journald 管,不要让脚本自己写

我早期的写法是脚本里 console.log 一份、run.sh 里再重定向一份,结果同一个文件里每行都出现两遍,排查时还以为是任务被触发了两次。现在统一成脚本只往 stdout 写,由 journald 收:

journalctl -u myjob.service --since today --no-pager

需要长期留档再单独配 SystemMaxUse= 限额,而不是让脚本自己 roll。原因很简单:自己 roll 的日志在崩溃时最容易丢,而崩溃恰恰是最需要日志的时候。

四、把「执行结果」结构化落盘

日志是给人看的,报告是给程序看的。我的做法是任务结束时写一个固定 schema 的 JSON:时间戳、每个子任务的 OK/FAIL、失败原因、关键数值的前后对比。邮件或告警渲染器只读这个文件,不再去 grep 日志。

这么做的好处是「报告」和「执行」解耦:任务崩了也能发一封说明崩在哪一步的信;而渲染脚本可以单独用 --dry-run 跑,不用真去触发任务。踩过一次坑:渲染器原来只看 errors 数组,任务级的失败写在 actions 里,于是每天都发「全部成功」的假喜报。后来把两条路径统一成同一份结构化数据,这类误报才彻底消失。

五、开工前的环境自检要写进脚本

定时任务失败的绝大多数原因不是业务逻辑,而是环境:依赖的服务没起、凭据过期、某个外部通道断了。这些检查如果写在文档里靠人记,一定会漏。写成脚本里的前置断言,失败就带明确原因退出,比事后翻日志便宜得多。

小结

无人值守任务的可靠性,靠的不是某一个技巧,而是几条固定习惯:timer 打开 Persistent 且加抖动、互斥交给 flock 并保证 -n、超时用 control-group 收干净、日志交给 journald、结果落结构化 JSON、开工先做环境断言。这六条加起来不到二十行配置,却能把「每天要人看一眼」变成「只在真出问题时才看」。

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

评论(0)

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

全部回复

上滑加载中

设置昵称

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

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

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