iT邦幫忙

2026 iThome 鐵人賽

DAY 29
0
自我挑戰組

30 天養大一個開源專案:baodao-skill 從零開始系列 第 29 篇

【Day 29】15 次紅燈拆開來看:10 次是 counts 步驟的基準數太死,5 次是 URL 檢查

  • 分享至 

  • xImage
  •  

Day 28 我寫了「26 次裡有 15 次紅燈,沒有逐一追原因」。這次補上。從 Actions API 把 15 個紅燈排程 run 的失敗步驟全部撈出來,再對照 CHANGELOG 和 issue,看每一次到底是什麼壞掉。寫稿時(2026-10-06 03:44 KST)最新的排程 run 仍是 10/4 的 #77,綠燈。

用 API 一次列出失敗的步驟

runs 端點只給整個 run 的結論,失敗的是哪個步驟要再打 /runs/{id}/jobs。腳本如下:

import json, urllib.request, urllib.error

def get(u):
    try:
        return json.load(urllib.request.urlopen(u, timeout=30))
    except urllib.error.HTTPError as e:
        raise SystemExit(f'GitHub API {e.code}: {e.read().decode()[:100]}')

B = 'https://api.github.com/repos/tahodev/baodao-skill/actions'
runs = get(B + '/runs?event=schedule&per_page=100')['workflow_runs']
for r in sorted(runs, key=lambda r: r['created_at']):
    if r['conclusion'] != 'failure':
        continue
    jobs = get(f"{B}/runs/{r['id']}/jobs")['jobs']
    bad = [s['name'] for j in jobs for s in j['steps'] if s['conclusion'] == 'failure']
    print(r['created_at'][:10], r['run_number'], r['head_sha'][:7], bad)

2026-10-06 03:44 KST 實測輸出(共 15 行,列出前後各幾行):

2026-09-09 1 c49eedc ['Check URLs in SKILL.md files']
2026-09-16 11 fcfa13f ['Check URLs in SKILL.md files']
2026-09-20 36 e797d51 ['Re-verify headline record counts']
2026-09-25 41 e797d51 ['Re-verify headline record counts']
2026-10-02 63 c97ec91 ['Re-verify headline record counts']

15 次的失敗步驟都只有一個,沒有同時壞兩個的:9/9 到 9/16 的 5 次是 Check URLs in SKILL.md files,9/20 到 10/2 的 10 次是 Re-verify headline record counts。

10 次 counts:不是資料壞了,是我把會漂的數字寫成死值

Re-verify headline record counts 這步會拿線上資料的總筆數,跟腳本裡寫死的基準數比。下面是這 10 次對照 CHANGELOG 的結果:

日期(排程 run 的 UTC 日期) 次數 失敗的檢查 修法
9/20 到 9/25 6 停車場場數 exact-match 0.8.2:改成 ±5% 的 WARN
9/29 到 10/1 3 醫院診所總數寫死 37,133,實際 37,175 0.8.4:總數漂移改 ±5% WARN
10/2 1 醫院診所最後一頁:預期 177,實得 178 0.8.5:用最後一頁自己的 total 比對

這 10 次裡,9/20 到 9/25 的 6 次是同一個 commit(e797d51),倉庫沒有任何變動,紅燈連續六天,每天都是同一件事:公開資料在漂,我的基準數不漂。9/29 起的醫院診所也一樣:紅了三天才改成 ±5%,改完的隔天又因為同一份資料的最後一頁筆數差 1 筆再紅一次。每個修正都只處理眼前看到的那個數字,下一個會漂的數字還在後面。

整理出來的原則只有一條:線上資料的總筆數不是常數,不能用 == 比。現在 check-counts 的分法是:總數在 ±5% 以內不報,超過報 WARN,只有「回應成功旗標失敗、欄位缺失、總數掉到 3 萬以下、最後一頁筆數跟自己的 total 對不上」這類結構性問題才算 FAIL。

另外 5 次 URL:我只知道哪一步,不知道每次的原因

9/9、9/10、9/12、9/13、9/16 這 5 次失敗的步驟是 URL 檢查,issue #1 到 #3 的標題寫的是「lint or dead URL」。當時的 run log 我沒有逐一打開,所以這 5 次到底是哪個網址、什麼原因,我沒有證據可以寫。能確定的只有失敗步驟的名字,和 9/16 之後的排程 run 裡 URL 檢查沒有再失敗過。

錯誤處理

這個腳本一次最多打 1 + 15 次 API,未登入每小時只有 60 次額度。我在寫腳本前先用 curl -s https://api.github.com/rate_limit | jq -c .resources.core.remaining 看還剩幾次(當時是 49),跑完剩 38。腳本遇到 HTTPError(例如額度用完回 403)會印出狀態碼和訊息然後停下來,不會印一半的結果。

來源

  • 15 個紅燈排程 run 的清單:https://github.com/tahodev/baodao-skill/actions?query=event%3Aschedule
  • CHANGELOG(0.8.2、0.8.4、0.8.5 的條目):https://github.com/tahodev/baodao-skill/blob/main/CHANGELOG.md
  • issue #8:https://github.com/tahodev/baodao-skill/issues/8

上一篇
【Day 28】排程寫 12:17 UTC,26 次實測都晚了 3.2 到 7.4 小時才跑
系列文
30 天養大一個開源專案:baodao-skill 從零開始 共 29 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言