← 中文资源

简体中文版本

用死人开关心跳监控 Cron 任务

仅在计划任务成功后发送心跳,心跳迟到即触发告警,让静默失败的备份任务在预期窗口内被发现。

阅读英文原文

概述

Cron 只能报告它启动的命令的退出状态,无法发现 crontab 被删除、主机重建后没有恢复任务、任务在写文件前退出,或任务卡住不返回。死人开关反转信号方向:任务必须主动证明自己完成。若在计划时间加宽限期后仍未收到心跳,监控服务就告警。这能覆盖被删除的 crontab、停止的实例、过期的凭据和挂起的任务。心跳应在 pg_dump、文件非空检查和旧备份清理全部成功之后发送,而不是在任务开始时发送。

步骤

先通过 Healthchecks API 创建 cron 类型检查,设置每天 02:00 UTC 和 15 分钟宽限:

curl -sS -X POST https://healthchecks.io/api/v3/checks/ \
  -H "X-Api-Key: $HEALTHCHECKS_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"name":"nightly-billing-export","tags":"billing,cron","schedule":"0 2 * * *","tz":"UTC","grace":900}' \
  | jq '{name, schedule, grace, ping_url}'

脚本从权限为 0600 的 /etc/billing-backup.env 读取 DATABASE_URL 和 HEALTHCHECKS_PING_URL:

#!/usr/bin/env bash
set -euo pipefail

set -a
. /etc/billing-backup.env
set +a

PING_URL="${HEALTHCHECKS_PING_URL:?missing HEALTHCHECKS_PING_URL}"
OUT="/srv/backups/billing-$(date -u +%F).dump"

trap 'curl --fail --silent --max-time 10 "$PING_URL/fail" >/dev/null || true' ERR

pg_dump "$DATABASE_URL" --format=custom --no-owner --file="$OUT"
test -s "$OUT"
find /srv/backups -name 'billing-*.dump' -mtime +14 -delete

curl --fail --silent --show-error --max-time 10 --retry 3 "$PING_URL" >/dev/null

安装脚本并追加 crontab,保留已有任务:

(sudo crontab -l 2>/dev/null; echo '0 2 * * * /usr/local/bin/nightly-billing-backup.sh >> /var/log/billing-backup.log 2>&1') | sudo crontab -

验证

手动运行脚本,用 pg_restore --list "$(ls -t /srv/backups/billing-*.dump | head -1)" 确认归档有效。随后请求 $HEALTHCHECKS_PING_URL/fail 验证告警通道,再请求正常 ping 复位。用 Healthchecks API 查询:

curl -sS -H "X-Api-Key: $HEALTHCHECKS_API_KEY" https://healthchecks.io/api/v3/checks/ \
  | jq -r '.checks[] | select(.name == "nightly-billing-export") | [.status, .last_ping] | @tsv'

应输出 up 和最近的 ISO-8601 时间戳。

注意事项

主机时区与检查时区必须一致,否则每天都会误报;可设置 CRON_TZ=UTC。Cron 不加载登录 profile,脚本必须显式 source 环境文件并使用绝对路径。Ping URL 是持有即可用的密钥,不要写进 crontab,放在 root-only 文件里。心跳只能证明任务运行,不能证明备份可恢复,仍需定期执行 pg_restore 演练。外部服务不可用于隔离环境时,应自建 Healthchecks。