如何在 2026 年监控 Cron Jobs:完整指南
Source: Dev.to
引言
Cron 任务是现代应用的无声勤工者。它们负责备份、清理数据、发送邮件、与 API 同步以及处理无数其他关键任务。但当它们失败时,往往是静默失败。
传统 Cron 的问题
传统的 cron 没有任何内置监控。你可以把输出记录到文件,例如:
0 2 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
但这意味着:
- 你必须记得去查看日志
- 日志会无限增长(磁盘空间问题)
- 出现故障时没有警报
- 只有在需要备份时才会注意到问题
Cron 的职责是按计划运行命令。它并不是用来告诉你这些命令是否真正成功的。
我们需要监控的内容
在监控 cron 任务时,我们关心以下几点:
- 它是否真的运行过?(任务被禁用、服务器宕机)
- 它是否成功完成?(退出码 0 与错误)
- 它是否准时运行?(服务器过载、资源限制)
- 耗时多久?(性能下降)
- 输出是什么?(错误、警告、统计信息)
方法 1:邮件提醒(基础)
最简单的做法是使用 cron 自带的邮件功能:
MAILTO=admin@example.com
0 2 * * * /usr/local/bin/backup.sh
优点
- 零配置
- 开箱即用
缺点
- 只在出现错误(STDERR 输出)时通知
- 需要邮件服务器配置
- 没有成功确认
- 多个任务会导致邮件泛滥
- 无法追踪历史或模式
结论: 适合只有 1‑2 个 cron 任务的个人项目。不可扩展。
方法 2:日志文件 + 手动检查
集中式日志让你拥有更多控制权:
#!/bin/bash
# backup.sh
LOG_FILE="/var/log/backup/$(date +%Y-%m-%d).log"
echo "[$(date)] Starting backup..." >> "$LOG_FILE"
if pg_dump mydb > /backups/db-$(date +%Y%m%d).sql; then
echo "[$(date)] Backup completed successfully" >> "$LOG_FILE"
exit 0
else
echo "[$(date)] ERROR: Backup failed" >> "$LOG_FILE"
exit 1
fi
优点
- 完全掌控日志
- 详细输出
- 有历史记录
缺点
- 仍需手动检查
- 没有实时警报
- 日志轮转复杂
- 磁盘空间管理
结论: 更好,但仍会错过故障。
方法 3:死亡开关(Dead Man’s Switch)模式
与其监控失败,不如监控成功。如果没有收到任务的信号,就说明出现了问题。
基本模式
#!/bin/bash
# backup.sh
MONITOR_URL="https://cronmonitor.app/ping/your-unique-id"
# Run your backup
if pg_dump mydb > /backups/db-$(date +%Y%m%d).sql; then
# Signal success
curl -fsS --retry 3 "$MONITOR_URL/success"
exit 0
else
# Signal failure
curl -fsS --retry 3 "$MONITOR_URL/fail"
exit 1
fi
在监控端,你设置预期的时间表:
- “这个任务应该每天凌晨 2 点 ping 我”
- “如果到 2:30 AM 仍未收到 ping,则报警”
- “如果 ping /fail,则立即报警”
优点
- 捕获所有故障模式(任务被禁用、服务器宕机、脚本错误)
- 实时警报
- 历史追踪
- 可从任何地方使用
缺点
- 需要外部服务
- 依赖网络连通性
- 可能产生费用(大多数免费层已足够)
结论: 生产系统的行业标准。
方法 4:完整监控解决方案
针对企业需求,将监控与可观测性结合:
#!/bin/bash
# backup.sh with full monitoring
MONITOR_URL="https://cronmonitor.app/ping/your-unique-id"
# Start signal
curl -fsS --retry 3 "$MONITOR_URL/start"
# Capture start time
START_TIME=$(date +%s)
# Run backup with output capture
OUTPUT=$(pg_dump mydb > /backups/db-$(date +%Y%m%d).sql 2>&1)
EXIT_CODE=$?
# Calculate duration
END_TIME=$(date +%s)
DURATION=$((END_TIME - START_TIME))
# Report results with context
if [ $EXIT_CODE -eq 0 ]; then
curl -fsS --retry 3 \
--data-urlencode "status=success" \
--data-urlencode "duration=$DURATION" \
--data-urlencode "output=$OUTPUT" \
"$MONITOR_URL"
else
curl -fsS --retry 3 \
--data-urlencode "status=fail" \
--data-urlencode "duration=$DURATION" \
--data-urlencode "output=$OUTPUT" \
"$MONITOR_URL"
fi
exit $EXIT_CODE

这为你提供:
- 成功/失败追踪
- 执行时长
- 输出日志
- 故障上下文
- 随时间的性能趋势
实际实现技巧
1. 处理网络问题
为监控 ping 添加重试和超时:
curl -fsS --retry 3 --retry-delay 5 --max-time 10 "$MONITOR_URL"
使用 -f 在 HTTP 错误时失败,-s 静默模式,-S 显示错误。
2. 不让监控破坏任务本身
将监控包装起来,使其不影响主任务:
# Run the actual job
/usr/local/bin/backup.sh
JOB_EXIT_CODE=$?
# Try to report status, but don't fail if monitoring is down
curl -fsS --retry 3 "$MONITOR_URL" || true
# Exit with the job's actual exit code
exit $JOB_EXIT_CODE
3. 设置合理的宽限期
任务很少能在同一秒钟精确执行:
- 快速任务 (< 1 分钟): 5‑10 分钟宽限期
- 中等任务 (5‑30 分钟): 15‑30 分钟宽限期
- 长任务 (数小时): 1‑2 小时宽限期
4. 监控监控系统
如果主要监控服务宕机,准备备份方案:
PRIMARY_MONITOR="https://cronmonitor.app/ping/abc123"
BACKUP_MONITOR="https://backup-service.com/ping/xyz789"
curl -fsS --retry 2 "$PRIMARY_MONITOR" || \
curl -fsS --retry 2 "$BACKUP_MONITOR"
5. 使用环境变量
避免在脚本中硬编码 URL:
# /etc/cron.d/backups
MONITOR_URL=https://cronmonitor.app/ping/abc123
0 2 * * * user /usr/local/bin/backup.sh
#!/bin/bash
# backup.sh
if [ -n "$MONITOR_URL" ]; then
trap 'curl -fsS "$MONITOR_URL/fail"' ERR
# Your job here
curl -fsS "$MONITOR_URL/success"
fi
时区考虑
服务器、团队和监控服务可能位于不同的时区。最佳实践: 在 cron 调度中使用 UTC,并在监控工具中转换为本地时间。
# Server in UTC, backup at 2 AM EST (7 AM UTC)
0 7 * * * /usr/local/bin/backup.sh