為什麼需要這個機制
MES 呼叫 SAP 入庫 API 時,發生 Timeout 不代表 SAP 一定失敗
有可能 SAP 已經完成入庫並 Commit,只是 Response 在回傳途中遺失
Scroll sideways · 可左右捲動查看完整圖表
Mermaid · 圖表原始碼
sequenceDiagram
participant MES
participant SAP
MES->>SAP: 入庫 Request
SAP->>SAP: 執行入庫
SAP->>SAP: Commit
SAP--xMES: Response Timeout此時 MES 無法確認結果
如果 MES Retry,而 SAP 又重新執行一次,就可能造成重複入庫
解法:Transaction ID
MES 在第一次送出 Request 前,先產生唯一的 transactionId
例如:
transactionId = ABC123
只要是同一次業務操作的 Retry,都必須沿用同一個 transactionId
Scroll sideways · 可左右捲動查看完整圖表
Mermaid · 圖表原始碼
sequenceDiagram
participant MES
participant SAP
MES->>MES: 產生 transactionId = ABC123
MES->>SAP: 入庫 API + ABC123
SAP->>SAP: 檢查 ABC123
alt 第一次收到
SAP->>SAP: 執行入庫
SAP->>SAP: 保存 ABC123 + 處理結果
SAP->>SAP: Commit
SAP--xMES: Response Timeout
end
MES->>SAP: Retry + ABC123
SAP->>SAP: 發現 ABC123 已完成
SAP-->>MES: 回傳第一次處理結果第二次收到相同 transactionId 時,不再重新執行入庫
Retry 與新操作的差異
Retry 必須使用相同的 Transaction ID
新的業務操作則必須使用新的 Transaction ID
Scroll sideways · 可左右捲動查看完整圖表
Mermaid · 圖表原始碼
sequenceDiagram
participant MES
participant SAP
MES->>SAP: ABC123 / 數量 5
SAP->>SAP: 執行一次入庫
MES->>SAP: ABC123 / 數量 5
SAP-->>MES: 回傳原本結果
MES->>SAP: DEF456 / 數量 5
SAP->>SAP: 視為新的入庫操作因此規則很簡單:
同一次業務操作 Retry
= 相同 Transaction ID
新的業務操作
= 新的 Transaction ID
不能只靠「數量相同、工單相同、時間接近」來判斷是否重複,因為兩筆看起來一樣的資料,也可能真的是兩次合法操作
實作上要注意
Transaction ID 紀錄與實際業務資料,最好在同一個 Transaction 內完成。
不建議:
執行入庫
Commit
保存 Transaction ID
Commit
因為如果兩個 Commit 中間發生錯誤,可能造成入庫已成功,但 Transaction ID 沒有被保存。
Retry 時就可能再次執行。
建議流程:
Scroll sideways · 可左右捲動查看完整圖表
Mermaid · 圖表原始碼
sequenceDiagram
participant API
participant DB
API->>DB: Begin Transaction
API->>DB: 建立 ABC123 紀錄
API->>DB: 執行入庫資料更新
API->>DB: 保存處理結果
API->>DB: Commit
Note over API,DB: 業務資料與冪等紀錄一起提交另外,transactionId 應該有 Unique Constraint,避免同一個 ID 在併發情況下被重複執行。
完整流程
Scroll sideways · 可左右捲動查看完整圖表
Mermaid · 圖表原始碼
sequenceDiagram
participant MES
participant SAP
MES->>MES: 產生 ABC123
MES->>SAP: Request + ABC123
SAP->>SAP: 檢查 Transaction ID
alt ABC123 不存在
SAP->>SAP: 執行入庫
SAP->>SAP: 保存結果
SAP->>SAP: Commit
SAP-->>MES: 回傳結果
else ABC123 已完成
SAP-->>MES: 回傳之前的結果
end結論
核心原則是:
MES 可以重送 Request,但 SAP 不能重複產生業務效果transactionId 的目的,是讓 MES 與 SAP 都能確認:
這次 Request,到底是同一筆操作的 Retry,還是一筆全新的業務操作簡單來說:
HTTP Request 可以送很多次
實際業務操作只能成功一次
這樣可以避免 Timeout、Retry 或 Response 遺失造成重複入庫,同時也能保留真正合法的多筆入庫操作。