MySQL TaskStore node_executions 實作前確認
1. 文件目的
本文件用來啟動目標模式下的下一個第二階段工作節點:MySQL TaskStore node_executions 第一版。
本文件只做實作前確認,先固定欄位、索引、交易策略、測試範圍與停止線;不直接建立資料表、不執行 DDL、不連真實 DB、不修改 ITaskStore public method 簽章,也不修改 TaskExecutionRecord / TaskNodeExecutionRecord public model。
2. 目前已具備能力
| 項目 | 狀態 | 說明 |
|---|---|---|
task_executions | 已完成第一版 PoC | 已完成 Save upsert、FindById / ListRecent、fake gateway 測試與真實 DB manual-only 驗證。 |
TaskExecutionRecord.NodeRecords | 已完成 | 已可保存節點摘要,包含 NodeId、NodeName、DeviceId、CommandName、Status、RetryCount、TimeTakenMs、DataSummary、MetadataSummary、NextNodeId、TransitionSummary。 |
TaskExecutionRecord.Restore | 已有 internal helper | 可供 Infrastructure.MySql 還原任務摘要,不新增 public API。 |
MySqlTaskStoreSqlBuilder | 已完成第一版 | 目前只產生 task_executions SQL。 |
IMySqlTaskStoreGateway | 已完成第一版 | 目前支援 non-query、single row、list row;仍以 fake gateway 測試為主。 |
| Schema Attribute / SQL Generator | 已完成第一輪 | 可用 C# class 表達 table / column / index / comment,並產生 MySQL 5.6.2 相容 SQL。 |
3. 本批目標
本批建議只做 node_executions 節點摘要持久化,目標如下:
- 新增
node_executionsschema class,讓欄位、索引與描述可由 C# 維護。 - 擴充 MySQL TaskStore SQL builder,支援節點寫入 SQL。
MySqlTaskStore.Save(record)保存task_executions後,同批保存record.NodeRecords摘要。- 使用 fake gateway 測試 SQL、參數、節點順序與敏感資訊遮蔽。
- 不要求
FindById/ListRecent第一批立即完整載入節點明細。 - 真實 MySQL 寫入驗證另列 manual-only 驗證節點,需使用者確認 gate 後才執行。
4. 本批可以做
| 項目 | 是否可做 | 理由 |
|---|---|---|
新增 node_executions schema class | 可以 | 只定義 expected schema,不直接執行 DDL。 |
| 新增節點 SQL builder method | 可以 | 屬 Infrastructure.MySql 內部 SQL 產生,不改 Core contract。 |
| 新增 node row / parameter mapper | 可以 | 由 TaskNodeExecutionRecord 轉成 MySQL 參數。 |
| 擴充 fake gateway 測試 | 可以 | 不連真實 DB,適合作為第一批安全驗證。 |
Save 同批保存任務與節點摘要 | 可以 | 使用既有 ITaskStore.Save(record),不新增 public method。 |
| 更新文件與實作紀錄 | 可以 | 讓文件 repo 後續可同步顯示完成狀態。 |
5. 本批暫不做
| 項目 | 暫不做原因 |
|---|---|
不修改 ITaskStore public method | 避免擴大 Core contract。 |
不修改 TaskExecutionRecord / TaskNodeExecutionRecord public constructor 或 property | 現有節點摘要已足夠做第一版。 |
| 不保存 RawRequest / RawResponse | 這些資料目前最完整來源在 WorkflowNodeExecutionSnapshot / LogEntry,不屬本批。 |
不實作 command_executions | 命令明細資料來源尚未定案。 |
不實作 task_log_traces | 詳細 log 應由 DB LogWriter / TraceStore 承接,不塞進 TaskStore。 |
| 不接 ConsoleHost / ServiceHost 啟動流程 | 第二階段仍維持 Infrastructure 行為驗證,不導入正式 host。 |
不執行 CREATE TABLE / ALTER TABLE / DROP TABLE | DDL 屬高風險操作,需另行確認。 |
6. 建議資料表定位
| Table | 定位 | 第一版責任 |
|---|---|---|
task_executions | 任務主檔 | 任務狀態、Workflow、時間、結果摘要。 |
node_executions | 節點摘要 | 任務內每個節點的執行順序、狀態、設備命令摘要與轉移摘要。 |
node_executions 第一版是 TaskStore 的明細表,不是詳細 log table。
7. 建議欄位
| 欄位 | 型別 | 必填 | 來源 | 描述 |
|---|---|---|---|---|
task_id | varchar(64) | 是 | TaskExecutionRecord.TaskId | 任務識別碼,與 task_executions.task_id 對應。 |
sequence_no | int | 是 | NodeRecords 順序,由 1 開始 | 任務內節點執行順序。 |
node_id | varchar(64) | 是 | TaskNodeExecutionRecord.NodeId | Workflow 節點識別碼。 |
node_name | varchar(128) | 否 | TaskNodeExecutionRecord.NodeName | Workflow 節點名稱。 |
device_id | varchar(64) | 否 | TaskNodeExecutionRecord.DeviceId | 節點使用的設備識別碼。 |
command_name | varchar(128) | 否 | TaskNodeExecutionRecord.CommandName | 節點執行的設備命令名稱。 |
status | varchar(32) | 是 | TaskNodeExecutionRecord.Status | 節點執行狀態。 |
retry_count | int | 是 | TaskNodeExecutionRecord.RetryCount | 節點實際重試次數。 |
started_at | datetime | 是 | TaskNodeExecutionRecord.StartedAt | 節點開始時間。 |
ended_at | datetime | 否 | TaskNodeExecutionRecord.EndedAt | 節點結束時間。 |
time_taken_ms | int | 是 | TaskNodeExecutionRecord.TimeTakenMs | 節點耗時毫秒數。 |
error_code | varchar(64) | 否 | TaskNodeExecutionRecord.ErrorCode | 節點失敗時的錯誤代碼。 |
error_message | varchar(255) | 否 | TaskNodeExecutionRecord.ErrorMessage | 節點失敗時的錯誤訊息。 |
data_summary | text | 否 | TaskNodeExecutionRecord.DataSummary | 節點回傳 Data 摘要。 |
metadata_summary | text | 否 | TaskNodeExecutionRecord.MetadataSummary | 節點 Metadata 摘要。 |
next_node_id | varchar(64) | 否 | TaskNodeExecutionRecord.NextNodeId | 實際轉移的下一節點。 |
transition_summary | text | 否 | TaskNodeExecutionRecord.TransitionSummary | 節點轉移判斷摘要。 |
created_at | datetime | 是 | 寫入當下或 task updated time | 節點紀錄建立時間。 |
8. 建議主鍵與索引
第一版建議採複合主鍵:
PRIMARY KEY (task_id, sequence_no)
理由:
- 不需要新增 Guid 或流水號產生器。
- 可直接表示同一任務內的節點順序。
- 搭配 delete-and-insert 寫入策略時語意清楚。
建議索引:
| Index | Columns | 用途 |
|---|---|---|
idx_node_executions_task_id | task_id | 查詢指定任務節點歷程。 |
idx_node_executions_status | status | 查詢失敗或執行中節點。 |
idx_node_executions_device | device_id | 查詢某設備參與的節點。 |
idx_node_executions_node_id | node_id | 查詢特定 Workflow 節點的執行紀錄。 |
備註:若 PRIMARY KEY (task_id, sequence_no) 已能支援 task_id 查詢,idx_node_executions_task_id 可在實作時評估是否保留;若為了可視化與文件一致性,保留也可以接受。
9. 寫入策略
第一版建議採 delete-and-insert:
MySqlTaskStore.Save(record)先 upserttask_executions。- 刪除同
task_id既有node_executions。 - 依
record.NodeRecords順序插入節點摘要。
理由:
TaskExecutionRecord.NodeRecords是目前完整節點摘要來源。- 任務 Save 目前具備覆蓋語意;同一
task_id重複保存時,節點明細也應反映最新狀態。 - 比逐筆 upsert 更容易避免舊節點殘留。
限制:
- 若未來需要保留歷史 Save 版本,
delete-and-insert不適合,需另行設計 version 或 event table。 - 真實 DB transaction 尚未實作前,不能讓刪除與插入中途失敗造成明細不一致。
10. 交易策略
第一版實作建議先拆成兩層:
| 階段 | 策略 |
|---|---|
| fake gateway 單元測試 | 驗證會依序建立 task upsert、node delete、node insert commands。 |
| 真實 DB manual-only | 需確認 gateway 是否以 transaction 包住 task upsert + node delete + node inserts。 |
若要實際導入 transaction,建議優先在 MySqlTaskStoreGateway 內新增 internal transaction method,不改 ITaskStore。
11. 查詢還原策略
第一版建議:
FindById可以維持只查task_executions,不立即載入NodeRecords。ListRecent必須維持輕量,只查任務主檔。- 節點明細查詢若要提供,建議後續新增 internal mapper 與獨立查詢設計,再評估是否擴充 public API。
原因:
ITaskStore.FindById目前沒有「是否包含明細」參數。ListRecent若每筆都載入節點,未來資料量可能過大。- 直接改 public API 屬於停止線,需使用者確認。
12. 測試策略
12.1 fake gateway 單元測試
| 測試 | 目的 |
|---|---|
Save_ShouldDeleteExistingNodeExecutionsBeforeInsert | 確認同一 task_id 重存時先刪舊節點。 |
Save_ShouldInsertNodeExecutionsInOrder | 確認 sequence_no 由 1 開始,順序符合 NodeRecords。 |
Save_ShouldMapNodeExecutionParameters | 確認 NodeId、DeviceId、CommandName、Status、RetryCount、DataSummary、MetadataSummary、NextNodeId、TransitionSummary 被寫入參數。 |
Save_ShouldSkipNodeInsertWhenNoNodeRecords | 沒有節點時只保存 task 主檔,不產生 node insert。 |
Save_ShouldTruncateNodeExecutionLongFields | 確認 varchar 欄位不超過 DB 長度。 |
Save_ShouldNotExposePasswordWhenNodeCommandFails | node command 失敗時錯誤訊息不得包含密碼。 |
12.2 schema / SQL 測試
| 測試 | 目的 |
|---|---|
NodeExecutionSchema_ShouldParseColumnsAndIndexes | 確認 schema class 可解析欄位、主鍵、索引、comment。 |
NodeExecutionSchema_ShouldGenerateMySql56Sql | 確認 SQL Generator 可產生 MySQL 5.6.2 相容 SQL。 |
12.3 manual-only 真實 DB 驗證
本批完成 fake gateway 後,真實 DB 驗證需另列節點,不自動執行。
建議驗證項目:
- 使用測試 DB
hs_device_control_test。 - 確認
node_executionstable 已由使用者建立或經確認後建立。 - 以 manual-only gate 寫入一筆含兩個節點的 task。
- 驗證
task_executions有一筆主檔。 - 驗證
node_executions有兩筆節點明細。 - 驗證 index / comment 可由 metadata inspector 讀出。
- 驗證測試資料 cleanup。
13. 必須停下確認的事項
以下任一項出現時,Codex 必須停下,不得自動執行:
- 修改
ITaskStorepublic method 簽章。 - 修改
TaskExecutionRecord/TaskNodeExecutionRecordpublic constructor 或 property。 - 對真實 DB 執行
CREATE TABLE、ALTER TABLE、DROP TABLE。 - 對真實 DB 執行未經確認的
INSERT、UPDATE、DELETE。 - 把真實 DB 測試加入一般 CI。
- 保存或輸出 password、完整 connection string、Token。
- 把
command_executions或詳細 log table 混進同一批。 - 修改 ConsoleHost / ServiceHost / WebApi 啟動方式。
- 新增正式背景服務或正式 API 邊界。
14. 建議實作順序
- 新增
NodeExecutionSchema或同等 schema class。 - 補 schema parser / SQL generator 測試,確認欄位、索引與 comment。
- 新增
MySqlTaskNodeExecutionRow或 node parameter mapper。 - 擴充
MySqlTaskStoreSqlBuilder,產生 delete nodes 與 insert node SQL。 - 擴充 fake gateway,讓測試可檢查多個 command。
- 修改
MySqlTaskStore.Save,保存 task 主檔後保存 node 摘要。 - 補 fake gateway 單元測試。
- 執行
dotnet test tests\HS.DeviceControl.Infrastructure.MySql.Tests\HS.DeviceControl.Infrastructure.MySql.Tests.csproj。 - 補實作紀錄與下一個 manual-only 驗證設計。
15. 本次確認結論
建議採用「先保存節點摘要,不急著回讀明細」:
node_executions第一版由TaskExecutionRecord.NodeRecords產生,不修改 Core public contract。- 主鍵建議採
task_id + sequence_no。 - 寫入策略建議採
task upsert + node delete-and-insert。 - 查詢第一版維持 task 主檔,節點明細查詢另行設計。
- 真實 DB table 建立與 manual-only 寫入驗證必須另行確認。
建議下一步進入「MySQL TaskStore node_executions 第一版實作」,但只做 schema class、SQL builder、fake gateway 與單元測試;遇到 DDL、真實 DB 寫入或 public contract 變更時必須停下。