如之前的篇章提到過,Workflow 程式碼必須是確定性的(Deterministic):給定同一份 Event History,重播必須產生相同的決策與結果。
也就是說當發佈新版本的 Workflow 程式碼時,如果邏輯或指令序列和舊版本不同,舊流程在重播 (Replay) 歷史時就可能發生「非決定性錯誤(NonDeterministicWorkflowError)」造成中斷。
為了安全地升級流程,Temporal 提供了「Workflow Versioning」機制:
Workflow.getVersion
顯式標記變更點以下列出需要版本化保護的變更清單:
類別 | 變更內容 | 是否需要 Workflow Versioning | 說明 |
---|---|---|---|
結構變更 | 新增/移除/改名 Activity 或 Child Workflow(包含更動 ActivityType 字串) |
✅ 需要 | 會改變排程指令(ScheduleCommand)結構,Replay 時不一致 |
執行參數 | 改變重試、超時、上限等 Activity/Workflow Options(如 RetryPolicy、Timeout、Heartbeat、TaskQueue) | ✅ 需要 | 這些設定會被寫入 Event History,影響 Replay 決策 |
控制流程 | 調整分支邏輯(if/else/switch )、迴圈次數、回呼註冊點、Signal 消費時機 |
✅ 需要 | 分支或判斷改變會導致事件序列不同 |
事件時序 | 更動 Timer/Signal/Query 的註冊順序、等待條件(例如 Workflow.await(...) 的條件) |
✅ 需要 | 會改變事件觸發順序或等待行為,Replay 產生不同事件流 |
非決定性來源 | 在 Workflow 中直接使用時間/亂數/UUID/外部 API(未透過 Activity 或可控 Clock) | ✅ 需要 | 非決定性行為導致 Replay 不一致 |
內部實作 | 純 Activity 內部實作修改(不改變 Workflow 端呼叫方式與選項) | ❌ 不需要 | Workflow 只關心指令序列,Activity 實作不影響 Replay |
重構優化 | 不改變指令序列與分支結果的重構(重命名、抽方法、結構調整、log 變更) | ❌ 不需要 | Replay 結果相同,屬安全重構 |
"payment-method"
、"ship-policy"
),同一位置沿用相同 id。Workflow.getVersion(changeId, DEFAULT_VERSION, maxVersion)
標記;舊歷史走 DEFAULT_VERSION
,新流程走 maxVersion
。getVersion
會被記錄並重播,呼叫次數與順序必須固定。import io.temporal.workflow.Workflow;
public class OrderWorkflowImpl implements OrderWorkflow {
@Override
public void run() {
// 以 changeId "payment-method" 標記此變更點,將最大版本設為 1
// 舊歷史重播會得到 DEFAULT_VERSION;新流程會得到 1
int v = Workflow.getVersion("payment-method", Workflow.DEFAULT_VERSION, 1);
if (v == Workflow.DEFAULT_VERSION) {
// 舊版本路徑:保持原指令序列,確保重播一致
chargeLegacy();
} else {
// 新版本路徑:套用新行為
chargeV1();
}
}
}
多次演進:
// 同一個 changeId,將最大版本提升到 2(v0→v1→v2)
// 保留所有已上線過的分支,直到舊歷史完全結束
int v = Workflow.getVersion("payment-method", Workflow.DEFAULT_VERSION, 2);
if (v == Workflow.DEFAULT_VERSION) {
chargeLegacy(); // v0:舊歷史重播
} else if (v == 1) {
chargeV1(); // v1:第一版新行為
} else if (v == 2) {
chargeV2(); // v2:第二版新行為
}
Workflow.getVersion(changeId, DEFAULT_VERSION, newMax)
。continueAsNew
,在安全點加速切換至新版本。滿足以下條件時,才能刪除舊版本邏輯:
continueAsNew
全數切到新程式碼。Temporal 核心是可重播的 Workflow。用版本化標記變更點,確保舊流程可重播、新流程走新行為;並配合可控放量與重播測試,達成不停機升級。