用 Bash 實作簡單的 cron 監控器
在 Linux 系統管理的世界裡,cron 無疑是最常用的排程工具。無論是定時備份資料庫、清理暫存檔案,還是定期執行資料同步,我們都依賴它來確保任務按時執行。然而,一個常見的痛點是:當 cron 任務失敗時,我們往往要等到下一個週期或事後查閱日誌才能發現。
對於系統管理員而言,「知道任務失敗了」比「修復失敗」更關鍵。今天,我們將透過一個簡單的 Bash 腳本,實作一個輕量級的 cron 監控器。這個腳本會檢查特定 cron 任務的執行狀態,並在異常時透過電子郵件或 Log 發送警報,確保你對系統狀態始終保持掌握。
為什麼需要監控 cron?
Cron 的預設行為是將標準輸出(stdout)和標準錯誤(stderr)寄送至使用者的 Mailbox。但在現代 Linux 環境中,許多伺服器並未啟動 MTA(郵件傳輸代理程式),這意味著即使任務失敗,你也可能收不到任何通知,或者日誌被丟棄在 /var/mail/ 中難以檢索。
此外,cron 任務可能因為路徑問題、權限不足或依賴的服務未啟動而失敗,但這些錯誤往往不會中斷後續的 cron 條目。因此,主動監控不僅能提升系統的可靠性,也能減少突發性災難發生的機率。
實作監控腳本
我們將建立一個名為 cron_monitor.sh 的腳本。這個腳本的核心邏輯是:檢查特定任務最後一次執行的時間戳記,並與當前時間進行比較。如果時間間隔超過預期,則判定為失敗或遺漏執行。
首先,讓我們建立腳本檔案:
#!/bin/bash
# cron_monitor.sh
# 簡單的 Cron 任務監控腳本
# 適用於 Ubuntu 22.04 / Debian 12
# 設定變數
TASK_NAME="my_backup_script.sh" # 你要監控的任務名稱或路徑
EXPECTED_INTERVAL=3600 # 預期執行間隔(秒),例如每小時執行一次設為 3600
MAX_LAG=3700 # 允許的最大延遲(秒),若超過此值則觸發警報
LOG_FILE="/var/log/cron_monitor.log"
ALERT_EMAIL="admin@example.com" # 警報接收信箱
# 取得該任務最後一次修改時間的 Unix 時間戳記
# 這裡假設任務會產生一個標記檔案,或我們直接監控任務腳本本身的執行記錄
# 為了通用性,我們假設任務會在 /tmp 下產生一個標記檔,例如 .task_completed
MARKER_FILE="/tmp/${TASK_NAME}_last_run"
# 如果標記檔案不存在,表示任務從未執行過
if [ ! -f "$MARKER_FILE" ]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') [ERROR] 任務 $TASK_NAME 從未執行過" >> "$LOG_FILE"
# 發送警報
echo "警告:任務 $TASK_NAME 從未執行過!" | mail -s "Cron Monitor Alert" "$ALERT_EMAIL"
exit 1
fi
# 取得標記檔案的最後修改時間(秒級)
LAST_RUN_TIMESTAMP=$(stat -c %Y "$MARKER_FILE")
CURRENT_TIMESTAMP=$(date +%s)
# 計算時間差
TIME_DIFF=$((CURRENT_TIMESTAMP - LAST_RUN_TIMESTAMP))
# 檢查時間差是否超過允許範圍
if [ "$TIME_DIFF" -gt "$MAX_LAG" ]; then
MSG="任務 $TASK_NAME 已逾時!最後執行時間:$(date -d @$LAST_RUN_TIMESTAMP '+%Y-%m-%d %H:%M:%S'),已過期 $((TIME_DIFF / 60)) 分鐘。"
echo "$(date '+%Y-%m-%d %H:%M:%S') [ALERT] $MSG" >> "$LOG_FILE"
# 發送警報郵件 (需系統安裝 mailutils)
echo "$MSG" | mail -s "Cron Monitor Alert: $TASK_NAME" "$ALERT_EMAIL"
exit 1
else
# 正常執行,可選擇記錄日誌或靜默
# echo "$(date '+%Y-%m-%d %H:%M:%S') [OK] 任務 $TASK_NAME 正常執行" >> "$LOG_FILE"
exit 0
fi
如何讓你的任務支援監控?
上述腳本依賴一個「標記檔案」來判斷任務是否執行。因此,你的實際 cron 任務(例如 my_backup_script.sh)需要在執行完畢後,更新這個標記檔案的時間戳記。
在你的備份腳本末尾加上這行指令:
touch /tmp/my_backup_script.sh_last_run
這樣,當 cron_monitor.sh 執行 stat 指令時,就能準確讀取到最後一次執行的時間。
設定 Cron 與權限
現在,我們將監控腳本本身也加入 cron,例如每 15 分鐘檢查一次:
-
賦予腳本執行權限:
chmod +x /usr/local/bin/cron_monitor.sh -
編輯 crontab:
crontab -e -
加入以下行:
*/15 * * * * /usr/local/bin/cron_monitor.sh
常見問題與解決方案
1. 收不到警報郵件?
在許多 Docker 容器或最小化安裝的 VPS 中,mail 命令可能未安裝或無法連線到 SMTP 伺服器。
- 解決方案:安裝
mailutils(Ubuntu/Debian):sudo apt install mailutils。或者,將腳本中的mail指令改為寫入日誌,並配合外部監控服務(如 Prometheus Node Exporter 或簡單的 HTTP webhook)發送通知。
2. 時區問題導致誤判?
stat 和 date 預設使用系統時區。如果伺服器時區設定錯誤,會導致時間計算偏差。
- 解決方案:在腳本開頭強制設定時區:
export TZ=Asia/Taiwan。建議所有 Linux 伺服器統一使用 UTC 時區,避免夏令時間帶來的困擾。
小結
透過這個簡單的 Bash 腳本,我們建立了一個輕量級且無需額外安裝依賴的 cron 監控機制。雖然它不如 Zabbix 或 Prometheus 強大,但在小型專案或個人伺服器上,這種「直接且透明」的監控方式往往更有效率。
關鍵在於「可觀察性」。當你能即時知道任務是否按時執行時,系統管理的壓力將大幅降低。你可以根據需求擴展這個腳本,例如加入 Slack Webhook 通知、檢查任務執行的退出碼,或監控磁碟空間變化。希望這篇文章能為你帶來靈感,讓你的 Linux 系統更加穩健可靠。