Skip to content

lifecycle:被逼停的關機走 BeginFailure;修好 kit/logging 會過期的測試 - #14

Merged
hoshimoe merged 2 commits into
mainfrom
claude/workspace-entry-focus-8bkczd
Aug 15, 2026
Merged

lifecycle:被逼停的關機走 BeginFailure;修好 kit/logging 會過期的測試#14
hoshimoe merged 2 commits into
mainfrom
claude/workspace-entry-focus-8bkczd

Conversation

@hoshimoe

Copy link
Copy Markdown
Member

兩件事,都與「日誌在什麼層級才看得到」有關。

1. lifecycle.BeginFailure

BeginShutdown 的 announce 一律 info,而採用它的服務把「是什麼逼停了我」
當成那一行的欄位傳進去。結果是:跑在 log.level: warn 的部署——也就是最需要
這筆紀錄的那些——listener 起不來時,那個 error 不存在於任何一筆 error 紀錄裡

行程就這麼消失,什麼都沒留下。

新增 BeginFailure(log, reason, err, attrs...)

  • 觸發的 error 走 Error,帶著是什麼掛了;
  • Done() 之後不會stopped cleanly,而是 stopped after a failure
    ——即使每個拆解步驟都成功。收拾得乾淨不等於停得乾淨,而在 warn 底下
    那行總結本來會是唯一活下來的一行;
  • errnil = 沒有東西逼停它 = 等同 BeginShutdown
    讓只有一條程式路徑的呼叫端不會意外變吵。

BeginShutdown 一個位元組都沒動:有秩序的停止維持 info,跑在 warn
部署看不到它是刻意的——例行重啟不該每次都喊。成功的拆解步驟也維持 debug

2. kit/logging 的測試從 2026-08-14 起單向轉紅

newRotator 建構時就 prune() 一次,而測試是在它回傳之後才裝 r.now
——那次 prune 用的是真實時鐘。「保留窗內」那個檔固定寫在 2026-07-31,
真實 cutoff(now−14d)越過它的那一天起就被刪掉了。不是 flaky,是單向過期。

把時鐘改成 newRotator 的參數(niltime.Now),在 prune 之前就位。
順帶讓那支測試真的涵蓋到啟動時那次 prune——它先前完全沒被測到,
因為斷言前又呼叫了一次 prune(),看起來像是那一次的功勞。

驗證

gofmt -l . 無輸出、go build ./...go vet ./...go test -race ./... 全綠;
js/npm test 33 passed / 0 failed(本次沒有動到 JS,那裡沒有 lifecycle)。

測試斷言的是某個層級的部署實際看得到什麼——建一個 Level: warn 的 logger、
寫進暫存檔、讀回來比對。這個差別debug 底下驗不出來,所以任何在預設
層級跑的測試都會是綠的。四支:warn 底下失敗關機聽得到(且成功步驟不會漏出來)、
warn 底下正常關機完全靜默、失敗的 step 即使在正常關機裡也是 error
nil cause 等同 BeginShutdown

實測反向對照:把原因行退回 info,第一支轉紅;還原後回綠。


Generated by Claude Code

newRotator 在建構時就 prune 一次(服務停機久於保留窗時要補刪),而測試是在
它回傳之後才裝上 r.now——那個時鐘來得太晚,那次 prune 用的是真實時鐘。
測試把「保留窗內」那個檔固定寫在 2026-07-31,於是真實時間越過
cutoff(now-14d)的那一天起,建構時的 prune 就把它刪掉了,測試從此
單向轉紅。臨界點是 2026-08-14。

時鐘改成 newRotator 的參數(nil = time.Now),在 prune 之前就位。
順帶讓這支測試真的涵蓋到啟動時那次 prune——它先前完全沒有被測到,
因為斷言前又呼叫了一次 prune,看起來像是那一次的功勞。

反向對照:拿掉保留期的刪除,測試在新的斷言上轉紅。
BeginShutdown 的 announce 一律 info,而採用它的服務都把「是什麼逼停了我」
當成那一行的欄位傳進去。結果是:跑在 log.level: warn 的部署——也就是最需要
這筆紀錄的那些——listener 起不來時,那個 error 不存在於任何一筆 error 紀錄裡,
行程就這麼消失,什麼都沒留下。

新增 BeginFailure(log, reason, err, attrs...):

- 觸發的 error 走 **Error**,帶著是什麼掛了;
- Done() 之後**不會**說 "stopped cleanly" 而是 "stopped after a failure",
  即使每個拆解步驟都成功——收拾得乾淨不等於停得乾淨,而在 warn 底下那行
  總結本來會是唯一活下來的一行;
- err 傳 nil 代表沒有東西逼停它,等同 BeginShutdown(單一程式路徑的呼叫端
  不會意外變吵)。

BeginShutdown 一個位元組都沒動:有秩序的停止維持 info,跑在 warn 的部署
看不到它是刻意的,例行重啟不該每次都喊。成功的步驟也維持 debug。

測試改成斷言**某個層級的部署實際看得到什麼**,而不是斷言呼叫了什麼——這個
差別只在 info 以上才存在,在 debug 底下驗不出來。四支:warn 底下失敗關機
聽得到(且成功步驟不會漏出來)、warn 底下正常關機完全靜默、失敗的 step
即使在正常關機裡也是 error、nil cause 等同 BeginShutdown。把原因行退回 info
可讓第一支轉紅,已實測。
@hoshimoe
hoshimoe merged commit f68b284 into main Aug 15, 2026
9 checks passed
@hoshimoe
hoshimoe deleted the claude/workspace-entry-focus-8bkczd branch August 15, 2026 15:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant