自動化靜默失敗檢查:排程回報成功卻什麼都沒做,先看這三點

發佈 2026-09-10 · 更新 2026-09-09 · 閱讀約 6 分鐘 · AI 工作術(法芮可有限公司)

排程跑完、節點全綠、通知也發了,資料卻一筆都沒進去——這就是自動化靜默失敗。本文用處理筆數、誰被通知、跑過 vs 跑成功三個檢查點,帶你 15 分鐘自檢爬蟲、AI 自動發文與各種排程,並附可直接照抄的告警與心跳設計、演練方式與常見誤區。

自動化最貴的 bug,不是那種跳紅字的。是它明明什麼都沒做,卻回報「成功」。排程跑完了、流程節點全綠、聊天室還準時推一則「今日同步完成」,結果資料庫一筆都沒進去。這叫靜默失敗(silent failure),它最討厭的特徵就是:所有你平常會看的指標,全部正常。

要抓它,別急著翻 log。先回答三個問題:這次到底處理了幾筆?失敗的時候誰會知道?這支程式是「跑過」還是「跑成功」?這三題答不出來,你的自動化就處在「壞掉了也不會有人發現」的狀態——只是還沒輪到你被抓包而已。

我們自己在營運 AI 工具站、自動剪片與廣告產製流程,前陣子花了一整天把手上幾套後端和排程掃過一遍,光是「例外接住了、寫一行 log、然後照樣往下走」的點就兩百多個,其中五十幾個是會寫資料庫的。真正把我們戳醒的是:那次出事不是監控發現的,是同事發現的。下面這三個檢查點,就是那輪自檢整理出來的最小可行版本,不需要導入任何監控平台,今天就能做。

靜默失敗長什麼樣?為什麼自動化特別容易中

一般的 bug 會炸給你看:程式停住、頁面白掉、Log 一整片紅。靜默失敗剛好相反,它把失敗吃掉,然後對外報成功。最常見的四種寫法:

  • 接住例外只寫 log 就走掉:`catch` 裡面只有一行「同步失敗」,沒有重拋、沒有告警,外層繼續往下跑。
  • 成功旗標放在錯誤處理外面:寫入包在 try 裡面,`saved = true` 卻寫在 try 外面,寫不寫得進去完全不影響對外回報。
  • 把「找不到」當成「成功」:資料庫刪了 0 筆、查詢回空陣列,程式直接 return,後台顯示「已刪除」。
  • 對第三方回呼失敗還回 200:金流、物流、社群平台的 Webhook 看到 2xx 就不會重送,那是你最後一次補救機會,被你自己丟掉了。

排程、爬蟲、AI 自動發文這類流程特別容易中,原因很單純:沒有使用者在看畫面。網站壞掉五分鐘就會有人喊,但一支每天早上七點跑的排程,連續兩週抓 0 筆也不會有任何人察覺。而且這類流程多半沒有 HTTP 狀態碼,你唯一的「它還活著」的證據,就是 log 檔的更新時間——而一支每次都炸掉的程式,traceback 也是寫進 log,更新時間看起來跟健康的一模一樣。

你以為實際上可能是
通知說「同步完成」完成了流程,但處理 0 筆
Log 每天都有更新每天都在寫同一段 traceback
排程狀態顯示成功程式 exit 0,但內部逐筆都失敗
CI 是綠燈那條流程根本沒跑測試
爬蟲有寫檔案寫進去的是空陣列,覆蓋掉舊資料

檢查點一:處理筆數——沒有數字的「成功」都不算成功

處理筆數要怎麼報:通知一定要帶「掃了幾個、成功幾筆」、0 筆分兩種:沒新資料 vs 沒掃到、連續 3 次 0 筆就自動告警、比前 7 天均值少 80% 也要叫、讀舊狀態失敗時,絕不可用空值覆寫
處理筆數要怎麼報

這是投報率最高的一條,而且不用改架構:凡是自動化流程的對外回報,都必須帶數字。「完成」是描述動作,「筆數」才是描述結果,而靜默失敗剛好就是「動作有做、結果是空的」。

把通知訊息改掉就對了:

  • ❌ 「今日資料同步完成 ✅」
  • ✅ 「同步完成:掃描 12 個來源,新增 34 筆,略過 2 筆(已存在),失敗 0 筆,耗時 48 秒」

差別在哪?第二種訊息,你掃一眼就知道不對勁——平常新增三十幾筆,今天寫「新增 0 筆」,你會立刻點進去看。第一種訊息永遠長一樣,壞掉了你也看不出來。

0 筆有三種完全不同的意思

這是最容易被混在一起的地方。抓到 0 筆可能是:(1) 今天真的沒有新資料(2) 來源網站改版,選擇器抓不到東西(3) 你的篩選條件寫錯,全部被過濾掉。第一種是正常,後兩種是壞了,但在通知上它們長得一模一樣。

解法是把「掃了幾個目標」和「成功處理幾筆」分開報。掃描 12 個來源、新增 0 筆,那大概是真的沒新資料;掃描 0 個來源、新增 0 筆,那是設定檔讀取失敗或清單腐爛了,必須告警。監控程式回報時只要看到「檢查了 0 個目標」就該叫,不能安安靜靜結束。

加兩條門檻,不用寫複雜邏輯

  1. 連續 N 次 0 筆就告警:通常設 3 次。真的沒新資料連續三天很少見,選擇器壞掉連續三天很常見。
  2. 比前 7 天平均少 80% 就告警:抓到「部分失敗」用的。爬 10 個來源掛了 8 個、還剩 2 個有資料,總數不是 0,靠前一條抓不到。

還有一條血淚規則:讀取舊狀態失敗時,絕對不可以拿空值繼續寫回去。「讀舊檔 → 合併新資料 → 覆寫」這個流程,如果讀舊檔那步被 catch 吃掉並回傳空陣列,你就會拿一份空的東西覆蓋掉累積好幾個月的資料,而且流程還回報成功。我們就遇過一次,一千多筆資料就這樣蒸發。寧可這一輪不存,也不能毀掉整份檔案。

檢查點二:誰被通知——log 寫在機器上,沒人看就等於沒寫

告警的三層防線:重拋或回錯:失敗不准回 2xx、送告警:走 webhook 進你每天看的頻道、落待辦紀錄:留一張可重跑的表、告警器自己絕不 throw、要能自曝失敗、同指紋去重 + 每小時上限,避免洗版
告警的三層防線

「我有記 log 啊」是最常見的自我安慰。log 檔要有人打開才叫監控,而現實是沒有人會每天早上主動 ssh 進去 tail 一個檔案。所以規則很硬:禁止「接住例外 → 寫 log → 什麼都不做」。接住之後,下面三件事至少要做一件:

  1. 重拋或回錯給呼叫端——讓上游知道這件事沒成,該重試就重試。
  2. 送告警——走一個 Webhook 打進你每天會看的地方:Slack、Lark、Discord、Telegram 都行。
  3. 落一筆待處理紀錄——寫進一張表,標記「這筆待重跑」,而且要能重跑。

做告警器的四條要求

我們自己的做法是抽一支 `reportSilentFailure(context, err, extra)`,所有刻意要吞的例外一律呼叫它,不准用裸的 log。這樣還有個額外好處:「專案裡哪些地方是刻意吞的」隨時 grep 得出來。告警器本身要滿足:

  • 自己絕不 throw:告警器把主流程弄掛,比沒有告警更糟。
  • 自己送不出去時要印明顯標記(例如 `[ALERT-DELIVERY-FAILED]`):連告警失敗都靜悄悄,那是套娃式靜默失敗。
  • 同指紋去重 + 每小時上限:一支壞掉的端點一分鐘噴三百則,你三天後就會把那個頻道靜音,等於沒有告警。
  • 送出前遮蔽敏感資料:別把整包 request body 倒進去。我們掃過一份 error log,裡面躺著幾十筆明文密碼和會員 email,原因就是登入失敗時把整包參數寫進去了。

另外三個會踩的坑

一、log 一定要帶錯誤本體。寫死一句「上傳失敗」等於沒寫,事後完全無法診斷。而且要實際看一行輸出來驗證——有些 log 套件的格式設定只印訊息字串,你傳進去的錯誤物件整個被丟掉,寫的人以為記了,實際上沒有。驗證方式是去看真實輸出,不是看程式碼。

二、錯誤處理那段程式碼自己要防爆。我們遇過錯誤處理中介層去讀一個在特定情況下不存在的欄位,結果處理器自己丟例外,那筆錯誤完全沒進 log——最需要被記錄的那種錯誤,剛好是唯一記不到的。

三、對平台回呼別亂回 200。做社群自動化時特別要注意,平台有自己的重送機制和額度規則,你回 2xx 就代表「我收到了、處理好了」。這塊的細節我們在 IG 留言自動回覆私訊完整流程 裡有展開講,包含防迴圈和額度耗盡時該怎麼回應。

檢查點三:跑過 vs 跑成功——讓 exit code 說實話

排程系統判斷成敗只看一件事:exit code。而大多數人寫排程腳本的方式是「逐筆處理,單筆失敗就 catch 起來繼續下一筆」——立意良好,但如果結尾直接跑完就結束,exit code 永遠是 0,監控看到的永遠是成功,就算 100 筆全掛也一樣。

修法只有一行:

  • 逐筆 catch 沒問題,但要累計失敗數
  • 結尾判斷:失敗數 > 0 就以非 0 結束(`sys.exit(1)` / `return self::FAILURE` / `os.Exit(1)`)。

這條規則對「測試」本身同樣適用,而且更容易被忽略。一支印出「有失敗 ❌」然後 exit 0 的測試腳本,它本身就是靜默失敗——誰跑都看到綠色,紅了多久都沒人知道。我們就有一支紅線閘測試,紅了不知道幾個月,因為所有人跑起來都是 exit 0。每支測試結尾請務必 `exit(0 if ok else 1)`,而且整個專案要有一鍵跑全部測試的入口,任一支紅就整體非 0——測試散在各處、要一支一支手動打的,實務上就是沒人會跑。

心跳:失敗才叫是不夠的

「失敗才告警」有個致命破口:如果排程根本沒被觸發,它連失敗的機會都沒有,自然也不會告警。機器重開沒起來、cron 設定被覆蓋、雲端帳號付款失敗導致 CI/CD 整個停擺——我們就親身遇過一次帳號付款問題讓自動化全數沒執行,整整兩天沒人發現,因為畫面上完全沒有紅字。

所以要反過來做心跳(dead man's switch):每次跑成功就打一個時間戳,另一支監控檢查「這個時間戳有沒有超過預期間隔」,超過就叫。邏輯是「該來沒來就叫」,不是「壞了才叫」。實作上再包一層 wrapper,記錄每次的 exit code 與連續失敗次數,連三次非 0 直接升級成緊急告警。

還有兩條很容易反覆踩的:監控器自己也要被監控——新增任何告警元件,同一回合就把它納入既有心跳,並且故意弄壞一次確認真的會叫,沒演練過的告警一律不算數。以及修補沒進版本控制等於沒修:只存在某一台機器磁碟上的修法,多台跑同一套時就會分岔成「你以為修好的 bug 還在另一台上跑」。回報「已修」之前,先確認 commit 了。

15 分鐘自檢:照這張表把你的自動化跑一遍

15 分鐘自檢五步:改壞來源跑一次,看會不會回報成功、跑完立刻 echo $?,確認失敗時非 0、故意斷網,驗證告警真的送得到、停排程一小時,看心跳有沒有叫、同批資料連跑兩次,確認不會重複寫
15 分鐘自檢五步

不用重構,照著驗一次就好。每一項都要親眼看到輸出,看程式碼推測不算。

#檢查項怎麼驗(15 分鐘版)沒過的症狀
1通知有沒有帶筆數翻最近三則通知,找得到數字嗎訊息永遠長一樣
20 筆會不會叫把來源網址改錯,跑一次照樣回報「完成」
3失敗時 exit code跑完馬上 `echo $?`內部有錯卻回 0
4告警真的會送達斷網或改壞 token,故意觸發聊天室毫無動靜
5log 有沒有帶錯誤本體打開 log 檔看實際那一行只有「xxx failed」
6有沒有心跳把排程停掉一小時沒有任何人發現
7重跑會不會重複寫入同一批資料連跑兩次比對數量資料變兩倍、重複發送

第 7 項特別提醒:沒有冪等就不能重跑。發券、扣款、開發票、發訊息這類動作重跑一次就是真的做了兩次,所以在做「失敗自動重試」之前,先確認有唯一鍵或去重表擋著,否則你只是把靜默失敗換成「安靜地多做了一次」。

五個最常見的靜默失敗現場

一、AI 自動發文只發出半篇或空白。模型回傳被截斷、被安全機制擋掉、或回了一段解釋而不是內容,程式收到的仍然是一個「合法的字串」,長度檢查沒做就直接發出去。至少加一道:字數低於門檻、缺少必要段落標記,就不准發,轉成待審。另外自動選題若沒設計機制,長期會嚴重同質化,這是內容層的隱形失敗,可以參考 用機制標籤法擺脫內容同質化 的做法。

二、爬蟲在來源改版後抓 0 筆,還把空值寫回去。前面講過,這是最會造成永久損失的一種。加上「筆數為 0 就不覆寫」這條硬規則,成本只有一行 if。

三、AI 產圖/產字幕「有東西但是錯的」。檔案有生成、大小正常、流程回報成功,但圖上的中文是錯字、數字被改掉。程式完全看不出來,只能靠人工抽檢或規則比對,細節可以看 AI 出圖中文錯字實測。這也是我們在做 AI 自動剪片 產線時最堅持的一點:輸出品質的關卡不能只靠「有沒有檔案」。

四、API 額度或 token 用完被誤判成「沒有資料」。429、餘額不足、金鑰過期,如果 catch 寫得太寬,全部會被歸成「這批空的」。成本與額度怎麼估、中文為什麼特別吃 token,可以參考 AI token 是什麼。順帶一提:catch 的範圍不可以比「你預期會失敗的那一行」大。本來只想處理「查不到資料」,結果連後面的寫入和記錄失敗一起吞掉,是我們自檢時最常見的一種。

五、同步到另一台機器前沒有先 diff。兩份不一樣可能是新舊之分,也可能是刻意分岔(某台有另一台沒有的功能),直接覆蓋會靜靜砍掉對方專屬邏輯。動手前先確認哪邊才是真實來源,並列出「只有線上有」的檔案清單。想找適合的排程與監控工具,可以逛逛我們整理的 AI 工具箱

常見問題

Q:我用 n8n、Make 這類無程式碼工具,也會有靜默失敗嗎?
會,而且更容易。這類工具的節點跑完就是綠的,但「回傳空陣列」對它來說也是成功執行。務必在流程末端加一個判斷節點:筆數為 0 或低於門檻就走告警分支,並且確認錯誤處理路徑不是預設的「忽略並繼續」。

Q:每個排程都加告警,會不會被訊息洗版?
會,如果沒做去重和上限的話。建議只在「狀態改變時」通知:從正常變失敗叫一次、從失敗恢復叫一次,中間持續失敗每小時最多一則。日常成功的紀錄改成每天一則摘要,把筆數放在裡面就夠了。被洗版的告警等於沒有告警,因為你一定會靜音它。

Q:只有我一個人的小專案,需要做到這樣嗎?
三個檢查點裡至少做兩個:通知帶筆數失敗時 exit 非 0,加起來不到半小時,但能擋掉大部分「壞了兩週才發現」的狀況。心跳可以先用免費的外部監控服務代替,不必自己寫。

Q:怎麼確認我的告警真的會叫?
只有一個方法:故意弄壞它一次。把金鑰改錯、把來源網址改成不存在、直接把排程停掉,看通知有沒有進來。沒有實際演練過的告警一律當作不存在——這點沒有捷徑,看程式碼是看不出來的。

Q:「處理 0 筆」到底要不要告警?
看你的資料節奏。如果來源每天穩定有新資料,0 筆就該叫;如果本來就會有空檔,改成「連續 3 次 0 筆」或「掃描目標數為 0」才叫。關鍵是把「掃了幾個目標」跟「成功幾筆」分開記錄,這兩個數字放在一起,你才分得出來是沒東西可做,還是根本沒做。

← AI 知識庫 · AI 工具庫