服务器定时任务别只写 cron:加锁、日志轮转与可观测性实践

举报
yd_217417492 发表于 2026/10/24 09:17:22 2026/10/24
【摘要】 cron 只负责按时触发,真正让定时任务长期稳定的是防重叠、日志轮转和可观测性。本文以一台小服务器上的监控脚本为例,给出可以直接复用的配置和排错思路。

为什么只写 cron 不够

很多服务器上的定时任务都是这样开始的:一行 crontab,脚本把结果追加到日志,能跑就行。短时间看不出问题,但运行几个月后,重复执行、日志撑满磁盘、失败了没人知道,这三类问题几乎一定会出现。下面以一台 2 核小服务器上的库存监控脚本为例,把这几件事一次做对。

一、先让任务不会重叠

监控脚本每 10 分钟跑一次,单次耗时偶尔会超过 10 分钟,比如网络超时后连续重试。这时 cron 会再拉起一个进程,两个实例同时写状态文件,就可能出现重复告警。最省事的办法是用 flock 加一把文件锁:

*/10 * * * * /usr/bin/flock -n /tmp/prize-watch.lock /usr/bin/python3 /opt/prize-watch/monitor.py --once >> /var/log/prize-watch/cron.log 2>&1

参数 -n 表示拿不到锁就立刻退出,不排队等待。这样同一时刻只会有一个实例在运行,也不会因为排队把任务越堆越多。

二、日志要能轮转,也要能追查

用 >> 一直追加的日志迟早会把磁盘写满。用 logrotate 按天切分、保留 14 天:

/var/log/prize-watch/*.log {
    daily
    rotate 14
    missingok
    notifempty
    compress
    delaycompress
    copytruncate
}

日志内容本身也要带时间戳,否则切分之后就不知道某次检查发生在几点。Python 里用 logging 配置 %(asctime)s 即可,不要只打印结果。

三、把「最后一次成功」写进状态文件

日志文件还在增长,并不代表任务健康。更实用的做法是每次运行结束都覆盖写一个 latest.json,记录检查时间、结果和耗时:

{
  "checked_at": "2026-10-24T09:00:03+08:00",
  "ok": true,
  "duration_ms": 812,
  "items": {"a": 0, "b": 0}
}

再配一条最简单的巡检规则:如果 checked_at 超过 30 分钟没有更新,就说明 cron 没跑或者脚本卡住了。这比判断「进程还在不在」可靠得多,因为进程可能活着但已经卡在网络请求上。

四、需要重试时,把重试放在脚本里

cron 本身不会重试。与其把执行频率调得很高,不如在脚本内部对失败的 HTTP 请求做两到三次指数退避,并给整体执行加一个超时。这样既不会堆积进程,也不会因为一次网络抖动就漏掉一整轮检查。重试次数和超时时间都要写进日志,方便事后判断是接口不稳定还是脚本逻辑有问题。

五、什么时候该换成 systemd timer

如果任务之间有依赖顺序、需要直观看到下次执行时间,或者要和其它服务一起管理,systemd timer 会更方便。systemctl list-timers 能直接列出上次和下次触发时间,输出也会自动进入 journald。只是对于「每 10 分钟跑一个脚本」这种简单场景,cron 加 flock 已经足够,没有必要为了迁移而迁移。

小结

定时任务真正难的不是按时触发,而是长期稳定地按时触发。加锁防止重叠、logrotate 防止爆盘、状态文件负责巡检,这三件事做好之后,一台小服务器上的定时任务基本就不需要人天天盯着了。

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

评论(0)

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

全部回复

上滑加载中

设置昵称

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

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

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