前幾天我們把財務日報、社群雷達、LINE 報告與知識庫同步都排進 Cron。表面上看,這些工作只要設定好時間與指令,系統就會每天自己跑。
但實際上,最常讓自動化失敗的,不是 Python 例外,也不是模型回答錯誤,而是認證在某個時間點悄悄失效。
Token 過期、OAuth refresh token 被撤銷、瀏覽器 session 消失、第三方平台要求重新登入,任何一件事都可能讓原本正常的工作突然變成空報告,甚至完全沒有交付。
先區分「程式失敗」與「資料拿不到」
一開始我們的判斷方式很直覺:Cron exit code 是 0,就視為工作完成。
這個判斷是錯的。
有些 CLI 在找不到資料時仍然可以正常結束;有些 API 回傳登入頁或空陣列,包裝腳本卻沒有把它視為錯誤;也有些工作只是把錯誤寫進 log,最後仍產生一份看起來格式完整的報告。
因此,認證檢查不能只看程序是否結束,至少要驗證三件事:
只有 exit code 0,代表程式結束,不代表資料真的可用。
我們建立 auth-auto-repair
後來把常用的外部服務集中放進每小時執行的 auth-auto-repair.sh,先檢查,再依服務特性選擇自動修復或通知人工登入。
目前檢查範圍包含:
| 服務 | 常見失效型態 | 處理方式 |
|---|---|---|
| LINE@ | chat.line.biz session 過期 | 嘗試恢復登入;需要人工時開啟登入頁 |
| gog OAuth token 失效 | 先做認證測試,必要時進入 refresh 流程 | |
| GitHub | CLI token 或權限失效 | 執行最小 API 檢查,失敗時標記人工處理 |
| NotebookLM | 瀏覽器登入狀態過期 | 保留來源與報告,通知重新登入 |
| X/xreach | Cookie 或 session 失效 | 先檢查登入,失敗時使用既定備援路徑 |
| Web session 過期 | 開啟登入頁,不猜測或保存帳密 |
這裡有一個重要原則:自動修復不是繞過登入,也不是把密碼寫進腳本。
能安全 refresh 的就 refresh;需要使用者互動的,就開登入頁並明確標記等待人工處理。密碼、Cookie、OAuth 資訊不輸出到報告,也不寫入文章或一般 log。
正式 Cron 前一定要做 preflight
每一個需要外部服務的正式工作,在開始抓資料前先執行 preflight。
流程如下:
例如財務日報不能因為 Google Sheet 認證失敗,就用昨天的資料或零筆資料產出今天的結果。正確行為是保留失敗原因、指出資料沒有更新,並等待認證恢復。
這個設計也避免另一種危險:認證剛好在工作中途失效,前半段資料成功、後半段資料失敗,最後卻被合併成一份不完整的報告。每個資料源都需要留下成功或失敗狀態,不能只看總程序是否完成。
登入恢復也要有停止條件
自動修復流程不能無限重試。
我們把結果分成三類:
可自動恢復:refresh token 有效,或服務允許非互動式重新取得 access token。
需要人工登入:服務要求瀏覽器互動、QR Code、PIN 或新裝置確認。這時只開啟固定登入入口,等待使用者完成,不猜帳密、不繞過驗證。
不可判斷:頁面改版、欄位不存在、回傳格式異常。這種情況停止,不重複點擊,也不把未知結果當成已登入。
每一類都要寫入可追蹤的狀態,例如最後檢查時間、服務名稱、失敗類型與下一步。報告不需要包含敏感憑證,但必須讓維運者知道該處理什麼。
真正的驗收是資料讀回來
這次改造後,我們把「完成」的定義從程序層提升到結果層:
本機變更:認證檢查腳本與 Cron 設定存在,語法與權限正確。
服務載入:Cron 實際載入最新設定,preflight 在正式工作前執行。
外部效果:讀回實際帳號、Sheet、聊天室或平台資料,確認不是登入頁、空回應或舊快取。
這也解釋了為什麼報告型自動化不能只回報「API 呼叫成功」。API 成功只是中間證據;使用者真正需要的是最新且完整的資料交付。
今天的實際證據
這套流程目前的核心驗證規則是:外部認證失敗時,不沿用舊資料冒充今日結果;可自動修復的服務先修復並重測;必須人工登入的服務保留未完成項目並開啟登入入口;重新登入後,才接續原本的工作。
自動化不是設定一次就永遠可靠。它更像一位需要值班制度的同事:每天有班表,也要先確認門禁、帳號與工具都能用。把認證當成正式依賴管理,而不是腳本裡最後才處理的例外,系統才不會在最需要它的時候安靜地失效。