iT邦幫忙

2026 iThome 鐵人賽

DAY 28
0
AI Engineering

打造具備記憶與執行能力的常駐 AI Agent:Hermes Agent × Gemini × MCP 的 Harness 設計系列 第 28 篇

【Day 28】Gateway 在跑、下次執行卻已過期 769 小時:排程任務的健康檢查

  • 分享至 

  • xImage
  •  

排程讓 agent 的動作從有人在場變成時間到就跑,出事時同樣沒有人在場,事後能看的只剩排程自己留下的紀錄。這一輪讀 hermes cron 各子指令留下什麼,量這台機器上五週的執行紀錄,再做一個完全不經過模型的週期檢查任務。


排程留下的紀錄各在哪裡

指令 回答的問題 資料位置
cron list 每個 job 的排程、下次執行時間、上次結果 cron/jobs.json
cron runs 每一次執行嘗試的狀態與錯誤訊息 cron/executions.db
cron incidents 失敗事件的生命週期,狀態為 detected、alerted、closed 指令輸出,附對應的 output 檔路徑
cron doctor job 的健康問題,例如下次執行時間已逾期 讀上列資料
cron status 排程器有沒有在跑 cron/ticker_heartbeat
每次執行的輸出 當次的 prompt 與回應全文 cron/output/<job_id>/<時間>.md

執行嘗試以持久紀錄保存,連終態寫不進去的那種也記成 unknown。


189 筆執行紀錄裡的失敗

cron runs --limit 500 列出 2026-07-31 到 2026-09-06 之間的全部嘗試,共 189 筆:

job completed failed unknown
door-fans-off-1100 7 6 0
door-fans-on-1105 9 5 0
env-status-telegram 150 10 2
合計 166 21 2

兩個定時開關風扇的 job 共 27 次,成功 16 次。jobs.json 裡的 repeat.completed 是 13 與 14,等於成功加失敗的次數(7+6、9+5),這個欄位計的是嘗試次數。

23 筆未完成的紀錄,錯誤訊息分成五種:

錯誤訊息 筆數
RuntimeError: Request timed out. 13
TimeoutError: Cron job ... idle for ...s (limit 600s) 4
模型的 context window 32,768 低於 Hermes 要求的 64,000 2
Context length exceeded,壓縮後仍超出 2
Scheduler restarted after this execution's owner exited ... 2

最後一種是 unknown 狀態的原文:

Scheduler restarted after this execution's owner exited before a durable terminal state; whether side effects ran is unknown

這句話對會操作設備的 job 有具體意義。執行到一半行程消失,排程器重啟後只知道這次嘗試沒有終態,風扇有沒有動得去讀感測端點才知道。

兩個風扇 job 最後一次成功是 2026-08-12,之後的四次嘗試全部失敗,cron list 顯示 4 failures in a row,依序是 Context length exceeded、context 低於下限、請求逾時、請求逾時。


排程器的兩個健康訊號

2026-10-09 12:47 的 cron status:

⚠ Gateway is running but the cron ticker looks STALLED — no heartbeat for 2838959s (expected every ~60s).
  PID: 2512
  Cron jobs may NOT be firing. Restart: hermes gateway restart

同一時間 cron doctor 對兩個風扇 job 各列出兩個問題,其中一個是:

next_run_at is 769.8h overdue — job is not firing (is the scheduler running?)

當下量到的狀態:

  • PID 2512 是一個執行中的 hermes_cli.main gateway run,啟動時間 2026-10-09 12:47:20
  • ticker_heartbeat 的內容停在 2026-09-06 16:11:52,2,838,959 秒約 32.9 天
  • jobs.json 與 executions.db 的最後寫入是 2026-09-06 11:07:59
  • gateway_state.json 記的 PID 是 11304,與現在這個行程不同,寫入時間同樣是 2026-09-06
  • logs/gateway.log 最後一行是 2026-09-06 13:11

行程存活與排程器在計時是兩個獨立的訊號。cron status 的警告句同時寫出 Gateway is running 與 ticker looks STALLED,兩句各自都是事實,成因無法從這些檔案判定。

Gateway 行程存在,不代表排程器在計時,兩個訊號要分開讀


不經過模型的任務

hermes cron create 有 --no-agent 與 --script:腳本就是任務本身,stdout 原樣投遞,空輸出代表靜默。以下是一個週期自我檢查,每次做兩件事:

  1. 跑 hermes security audit --json --fail-on high,把命中的 套件|漏洞編號 與基準比對
  2. 跑 hermes prompt-size --json,把工具 schema 的 byte 數與基準比對

判定失敗的條件是出現新的 HIGH 以上漏洞,或工具 schema 比基準大 10% 以上。腳本節錄:

env = {k: v for k, v in os.environ.items() if k != "HERMES_HOME"}

audit, audit_rc = hermes_json("security", "audit", "--json", "--fail-on", "high")
size, _ = hermes_json("prompt-size", "--json")

new_gated = {k: v for k, v in new.items() if v in {"HIGH", "CRITICAL"}}
growth = now["tools_bytes"] / base["tools_bytes"] - 1
fail = bool(new_gated) or growth > 0.10

lines = [f"# 自我檢查 {datetime.now().astimezone().isoformat(timespec='seconds')}"]
print("\n".join(lines))
sys.exit(1 if fail else 0)

第一行過濾 HERMES_HOME 有原因。排程在獨立的 HERMES_HOME 下跑時,腳本裡呼叫的 hermes -p default 仍然讀到那個目錄,config path 實測指向的是獨立目錄,不是預設 profile 的組態。

建 job 與兩次執行的結果:

hermes cron create --name selfaudit --no-agent --script selfaudit.py \
  --deliver local "0 3 * * *"
腳本印出的時間 條件 退出碼 cron runs incident
12:51:06 無基準檔 0 completed 無
12:51:48 基準檔刪兩筆漏洞、schema 基準改成 33,000 byte 1 failed detected,Type 為 script

第二次的失敗條件是人為製造的,用來走到失敗路徑。輸出如下:

# 自我檢查 2026-10-09T12:51:48+08:00
> 排程 0 3 * * *|元件 130|命中 60
- 新增漏洞 2 筆,其中 HIGH 以上 1 筆
- 工具 schema 37012 byte,相對基準 +12.2%
- 判定 FAIL

失敗時 stdout 整段進了 cron runs 的錯誤欄、incident 的 Error 欄位(顯示時截斷)與當次的 output 檔。投遞這一側,--failure-deliver 可以把失敗通知導向別的目標,說明寫的是 local 會完全抑制失敗通知,狀態仍可從 cron list 讀到,省略時失敗跟著 --deliver 走。

基準檔建立那次也順便量到漏洞的變化。前一輪在 10-04 量到 57 筆,同一組 130 個元件在 10-09 是 60 筆:

嚴重度 10-04 10-09
CRITICAL 2 2
HIGH 12 12
MODERATE 16 18
UNKNOWN 27 28

筆數增加的三筆來自 MODERATE(+2)與 UNKNOWN(+1),--fail-on high 的閘門維持原狀。新增的那筆 UNKNOWN 在任何門檻下都不會觸發閘門。

這個任務跑在沒有任何模型組態的 HERMES_HOME 下,由 CLI 的 cron run 與 cron tick 當下執行,兩次都照常完成,執行路徑上沒有推論端點。


寫死在 prompt 裡的時間

風扇 job 的第一個版本在 2026-08-05 12:24:46 手動觸發,排程是 0 11 * * *。那次的 output 檔記錄了 prompt 與回應:

**Run Time:** 2026-08-05 12:24:46
**Schedule:** 0 11 * * *

工具回傳 ok=true 時,最終訊息只輸出這一行:
已於 11:00 關閉前後門風扇(4 顆全部 OFF)

Response:
已於 11:00 關閉前後門風扇(4 顆全部 OFF)

回應與 prompt 範本裡的那一行逐字相同。「11:00」是 prompt 範本裡的字面內容,模型照抄,沒有生成任何時間。 排程準時觸發的執行落在 11:00 前後,字樣大致吻合,手動觸發時才與實際時間分開。

cron 在 prompt 前面加的前置段(You are running as a scheduled cron job. DELIVERY: ...)全文沒有日期或時間。現行兩個 job 的副標只寫 定時排程|每天 11:00,那是排程的定義,每次執行都為真。

要讓通知帶「實際執行時間」,來源得是讀系統時鐘的程式,上一節的腳本就是這樣做的,datetime.now() 每次印出的值不同。

通知裡的時間字樣取決於它從哪裡來,範本寫死的值在每一次執行都原樣出現


參考資料

概念 來源 年份
cron 子指令清單、create 的旗標與 --failure-deliver 語意 hermes cron --help、hermes cron create --help,Hermes Agent v0.21.0 2026
189 筆執行紀錄的分布與五種錯誤訊息 本機實測,hermes cron runs --limit 500,2026-10-09 2026
STALLED 訊息、769.8h overdue、心跳與狀態檔的時間 本機實測,hermes cron status、hermes cron doctor 與 cron/ 目錄檔案時間,2026-10-09 2026
無模型任務的兩次執行與 incident 本機實測,獨立 HERMES_HOME 下的 hermes cron create --no-agent,2026-10-09 2026
漏洞數量變化 本機實測,hermes security audit --json,2026-10-09,對照 2026-10-04 的量測 2026
手動觸發的輸出紀錄 本機 cron/output/ 下 2026-08-05 的執行紀錄 2026

心得

要試跑一個排程任務,第一個想到的指令是 cron tick。--help 對它的說明是「Run due jobs once and exit」,而 cron list 上兩個風扇 job 的下次執行時間是 2026-09-07 11:00,已經過期,到期的 job 會全部被執行一次,其中兩個會去操作真實的風扇。

試跑改在一個獨立的 HERMES_HOME 裡進行,那裡只有新建的那一個 job。tick 與 run 都只動得到那個目錄的 jobs.json。

這個做法本身帶出另一件事:同一台機器上,排程的狀態、紀錄與心跳全部以檔案存在 cron/ 底下,換一個 HERMES_HOME 就是另一個排程器。查排程有沒有跑,要先確認讀的是哪一個目錄。

試跑排程任務之前,先確認這個指令會一併觸發哪些已經到期的 job


明天

AMA-Bench、MemoryArena 這類評測基準量的是什麼,以及自己的驗收條件怎麼寫成機器判讀。


上一篇
【Day 27】設定好了跟會不會跑是兩個狀態:hook 的同意與掃描看不到的那一半
下一篇
【Day 29】測的是狀態而非回答:自建驗收題的設計與第一輪量測
系列文
打造具備記憶與執行能力的常駐 AI Agent:Hermes Agent × Gemini × MCP 的 Harness 設計 共 30 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言