跳轉到

Activity Framework Phase 3 完整實作:ClosureBuilder、Fleet Registry、Config Sync、Admin RPCs(融合版 v2)

文檔資訊

  • 分類: architecture
  • 難度: advanced
  • 預估閱讀時間: 14 分鐘
  • 標籤: activity-framework, golang, settlement, idempotency, fleet-registry, config-sync, bundle-admission, proto, twirp, phase3, coding-style, worktree

摘要

完整記錄 activity-framework Phase 3 的並行實作流程,包含 W6.1–W6.6 六個子任務的實作決策、Settlement 冪等性討論、RPC 契約落差分析、架構邊界技術見解,以及 coding-style.md 變數命名規則的執行案例(新增)。

關鍵學習

  • Settlement double-settle 風險的前提是 handler.SettlePlayer 做了 tx 外不可回滾的副作用(HTTP/MQ/push),framework 本身 tx 包覆是安全的

  • RPC 契約落差要區分「純文件同步」vs「真實語意缺口」:CreateManualActivity 缺少 source_key 的 idempotency 是真實缺口,不只是改名

  • handler fail-fast(DoD 要求 register 階段 fail-fast)更適合 infra 依賴,plugin-style handler 用 runtime ErrHandlerNotRegistered -> Unimplemented 是合理的 framework 邊界

  • GetFleetBundleStatus 排除 unready pod,用 3 consecutive heartbeat failure 偵測後 mark unready

  • Config Sync 用 advisory lock 序列化 + fingerprint 驗證防止並發衝突,content_mutation 會 block 整個 sync

  • ClosureBuilder 用 custom JSON encoder(非 encoding/json)保證 deterministic output,控制 float 格式與 time 格式

  • pkg/config/luban / cmd/nakama 的 build failure 用 git diff --name-status main 確認不是此 branch 引入,屬於 repo-wide merge blocker 而非 activity-framework 責任

  • coding-style.md 規定所有變數以小寫開頭(ctx、userID),subagent 產出的程式碼若出現大寫開頭變數即為違規,需強制修正

技術細節

六個並行子任務概覽

W6.1 ClosureBuilder - internal/modules/activity/activity_closure.go:custom deterministic JSON serializer,9 rules 包含 key ordering、array sort by ID、no trailing zeros on floats、RFC 3339 UTC - ComputeSpecHash(6 provisioning spec fields)與 ComputeContentHash(closure bytes SHA256) - Circular reference detection 用 DFS with white/gray/black coloring,O(V+E) - 使用 encoding/json 無法控制 float 格式與 time 格式,故採 custom encoder

W6.2 Fleet Registry - activity_fleet_registry_postgres.goRegisterPod, MarkPodReady, HeartbeatPod, MarkPodUnready, DeregisterPod, GetFleetBundleStatus, GetDivergentPods - RegisterAndStartHeartbeat:10s interval 心跳,3 consecutive failure 後 mark unready - wiring 用 SetFleetRegistry(fr) setter(post-Wire initialization,per architecture.md section 4.6)

W6.3 Bundle Admission Gate - ValidateBundleAdmission:對每個 live activity 驗證三件事:handler 已 register、ResolveContentClosure 成功、content_hash 比對 - ContentHash.Valid == false(NULL)視為 warning 非 hard failure,相容早期 activity - 回傳 AdmissionResult{Ready, Errors, Warnings},由 main.go Phase 3 決定如何處理

W6.4 Config Sync core - previewConfigSync:build diff → sorted SHA256 fingerprint - syncActivitiesFromConfigRunInTx + advisory lock,驗證 fingerprint,依 action 類型處理:create/update_schedule/drift(log-only)/orphan(cancel actions)/content_mutation(block) - UpdatePendingActionSchedule:prefix-match dedupe_key(pre_warm: / settle:)更新 scheduled_at

W6.5 ForceUpdateContentHash + ListActivities - GetAllActivities(ctx, source, includeArchived, now):optional source filter + archived exclusion - forceUpdateContentHash:get activity → resolve closure → SHA256 → update DB → invalidate cache - ListActivities 需 RoleAdmin,ForceUpdateContentHash 需 RoleSuperAdmin

W6.6 GetSettlementRunDetail - GetBatchesForRun(ctx, runID):query settlement_batches by run_id ordered by batch_index - getSettlementRunDetail:compose getSettlementStatus(run + progress)+ GetBatchesForRun(batches)

W8 測試覆蓋(新增)

151 tests pass,涵蓋 Bundle Admission Gate(7)、Config Sync Preview(9)、Config Sync Apply(5)、ForceUpdateContentHash(4)、ListActivities(3)、GetSettlementRunDetail(2)、Twirp Adapter(14 subtests)。

Coding Style 違規案例(新增)

subagent 在實作中產出了大寫開頭的變數名(違反 coding-style.md),使用者明確指出規則:所有變數一律小寫開頭,包含 ctxuserID 等。這是 subagent 生成程式碼時的常見漏洞,需在 review 時特別注意。

What Changed

PR 審查結論修正

初步審查提出 6 個問題,最終結論:

  • #1 double-settle:撤回,framework tx 包覆正確,唯一前提是 handler 不做 tx 外副作用
  • #2:非 bug,接受反駁
  • #3 line 922 測試:不是 bug,是 placeholder 行為的測試;但仍是「完整 scope 尚未完成」的佐證
  • #4 RPC 契約落差:分成「純文件同步」(Disable/Enable toggle、PauseDispatch→PauseSettlement)和「真實語意缺口」(CreateManualActivity 缺 source_key idempotency、GetSettlementRunDetail/ListActivities/ForceUpdateContentHash 實缺)
  • #5 測試覆蓋率:pkg/config/luban / cmd/nakama failure 確認不是此 branch 引入(git diff --name-status main 為空)
  • #6 handler fail-fast:改文件,不改 code;plugin-style handler 的 runtime ErrHandlerNotRegistered 是合理邊界

實作完成項目

6 個子任務全數完成,151 tests pass(W8 Config Sync tests),W9 文件更新含 RPC 名稱對齊(PauseDispatch→PauseSettlement、UnpauseDispatch→ResumeSettlement、EnableActivity→DisableActivity bool toggle、ClearOverride→OverrideEndTime clear_override=true)與 DoD checklist 標記。RBAC middleware 仍為 Hard Blocker(外部依賴)。

Coding Style 執行(新增)

subagent 實作過程中出現大寫開頭變數名,使用者強制要求修正,依據 coding-style.md 規則:所有 Go 變數一律小寫開頭。這個問題在 subagent 並行實作時容易被忽略,需在 code review 階段確認。

So What

這是一個複雜的 activity framework 從 Phase 2 升級到 Phase 3 的完整記錄,展示了如何在生產系統中同時推進多個獨立子系統(Fleet Registry、Config Sync、Bundle Admission Gate、ClosureBuilder),並且在過程中做出有依據的架構邊界決策。

新版增加了 coding-style.md 執行案例:subagent 並行實作時容易在變數命名上違規,使用者的執行態度明確——大寫開頭變數是不可接受的錯誤,不是可選建議。這個案例對未來使用 subagent 模式開發有重要的 code review 指導意義。

RBac middleware 仍為唯一 Hard Blocker,staging rehearsal 尚未能進行,但所有 Phase 3 功能本體均已完成。

Trade-offs

  • handler fail-fast vs runtime error:startup fail-fast 對 infra 依賴合適,但對 plugin-style handler 會過度限制擴充彈性;選擇 runtime ErrHandlerNotRegistered 讓 framework 邊界更清晰
  • custom JSON encoder vs encoding/json:encoding/json 在 Go 1.21+ map key 有排序,但 float 格式與 time 格式不可控;custom encoder 增加維護成本但保證 deterministic hash
  • content_mutation block 整個 sync:保守設計防止 drift 擴散,代價是需要 ForceUpdateContentHash + 人工審核才能解鎖
  • advisory lock + fingerprint:防並發衝突,但 preview→apply 之間若有變更會回傳 ErrConfigSyncConflict 要求重新 preview
  • subagent 並行實作:加速開發但需嚴格 code review,變數命名規則等 coding style 問題容易在自動生成程式碼中出現

Try It Fast

# 驗證 ClosureBuilder determinism
go test ./internal/modules/activity/... -run TestClosureBuilder -v -count=3

# 驗證 Bundle Admission Gate
go test ./internal/modules/activity/... -run TestBundleAdmission -v

# 驗證 Config Sync (preview + apply)
go test ./internal/modules/activity/... -run TestPreviewConfigSync -v
go test ./internal/modules/activity/... -run TestSyncActivitiesFromConfig -v

# 全模組測試(目標 151 pass)
go test ./internal/modules/activity/... -count=1
go test ./test/... -run Activity -count=1

# 確認 build failure 不是此 branch 引入
git diff --name-status main -- pkg/config/luban cmd/nakama

Recommendation

  1. RBAC middleware 是唯一剩餘 Hard Blocker,在此完成前 staging rehearsal 無法進行,應優先追蹤外部依賴進度
  2. subagent code review 必查項:變數命名一律小寫開頭(coding-style.md),subagent 生成的程式碼容易違規,尤其在並行任務模式下
  3. runbook 補充 resume 失敗語意:明確記載 ResumeSettlement 可能因 slot 被其他合法 run 佔據而失敗,這不代表系統異常
  4. handler 副作用規範:在 handler interface 文件中明確標注 SettlePlayer 不應做 tx 外不可回滾副作用(HTTP/MQ/push),否則需自行實作冪等
  5. content_mutation 解鎖流程:確保 runbook 有 ForceUpdateContentHash 的使用時機與審核流程說明
  6. pkg/config/luban / cmd/nakama build failure 雖非此 branch 引入,若 repo merge policy 是 repo-wide green 仍需在 PR 合併前解決,建議開獨立 issue 追蹤

本文檔由 Semi-Brain 自動生成

Session ID: 157b6880-f9d3-466a-abf9-07af0459b5d5

分析信心度: 93%