⏰ 第07章 · 定时任务实战

本服务器 cron + 日志

定时任务实战

这一章把 cron 用到这台服务器的真实场景上,讲几种"跑得稳"的写法:登录脚本、生成监控报告、备份、以及如何保证"只会跑一次""失败能知道"。学完你就能自己写出一套可靠的定时任务。

真实场景 1:每日自动化签到(本机示例)

贴吧签到脚本每天 07:00 执行:

0 7 * * * TIEBA_QUIET=1 /usr/bin/python3 /root/scripts/tieba_sign.py >> /var/log/tieba_sign.log 2>&1

要点:

  • TIEBA_QUIET=1:脚本里检测到该变量后只输出关键结果,不刷屏(适合 cron 后台跑)。
  • 重定向到日志文件:>> 追加覆盖可保留历史,> 会清空。
  • 用 2>&1 把错误也收进去,避免"静默失败"。

真实场景 2:生成并推送监控报告(本机示例)

监控报告脚本每天 08:00 执行:

0 8 * * * /usr/bin/python3 /root/scripts/monitor_report.py >> /var/log/monitor_report.log 2>&1

该脚本读取 /root/.feishu_monitor.conf 拿到飞书 Webhook/凭证,从 Prometheus 取数、画图、传给飞书群。日志里能看到它是否成功发送。

真实场景 3:定时备份

备份是最该自动化的事。示例(每天 02:00,先建目录再 mysqldump 导出全库):

mkdir -p /backups/mysql
0 2 * * * mkdir -p /backups/mysql && mysqldump --all-databases > /backups/mysql/all_$(date +\%F).sql

注意 | cron 里的 % 是特殊字符,要写成 \%。date +\%F 才能正确输出日期。建议把备份写成独立脚本,方便做"启动前清理旧备份、压缩、校验"。

更好的备份脚本 backup.sh:

#!/bin/bash
set -euo pipefail
BACKUP_DIR=/backups/mysql
mkdir -p "$BACKUP_DIR"
STAMP=$(date +%F_%H%M)
mysqldump --all-databases | gzip > "$BACKUP_DIR/all_${STAMP}.sql.gz"
# 只保留最近 7 份
find "$BACKUP_DIR" -name '*.sql.gz' -mtime +7 -delete
# 写日志
echo "backup ok $STAMP" >> /var/log/backup.log

并在 crontab 里:

0 2 * * * /bin/bash /root/scripts/backup.sh >> /var/log/backup.log 2>&1

真实场景 4:用 flock 防止任务重叠(关键!)

万一前一分钟的任务没跑完,下一分钟又开一个,会并发出错。用 flock 加锁,保证同一时间只有一个实例:

#!/bin/bash
exec flock -n /tmp/myjobs.lock /bin/bash /root/scripts/monitor_report.py

crontab 配上即可:

0 8 * * * flock -n /tmp/mon_report.lock /usr/bin/python3 /root/scripts/monitor_report.py >> /var/log/monitor_report.log 2>&1

重要 | 长时间任务(拉取数据、生成大数据)一定要加锁,否则上次任务还在跑,下次又启动,轻则资源占满,重则数据错乱。

真实场景 5:失败告警

cron 不会主动告诉你任务失败,所以要在脚本里"出错即告知"或"写失败标记":

#!/bin/bash
out=$(/usr/bin/python3 /root/scripts/tieba_sign.py 2>&1)
code=$?
echo "$out" >> /var/log/tieba_sign.log
if [ $code -ne 0 ]; then
    echo "myscript failed: $out" | mail -s "任务失败" you@example.com
fi

版本化与可维护性

  • 脚本统一放 /root/scripts/(集中管理)。
  • 每个脚本开头写清"用途 / 依赖 / 用法 / 配置位置"(参考本机这两个脚本的文件头注释)。
  • 日志统一放 /var/log/ 并配 logrotate(见《Linux 系统运维 · 日志管理》)防磁盘打满。
  • 用 systemd timer 也能替代 cron:需要"上次运行时间""失败重试"等高级特性时再上。

相关命令

  • crontab -l / crontab -e 管理; systemctl status cron 看服务。
  • flock 防并发; date +\%F 生成日期标签。
  • find ... -mtime +N -delete 清理过期备份。
  • mail -s/飞书/钉钉 Webhook 做失败通知。