iT邦幫忙

2025 iThome 鐵人賽

DAY 17
0
Software Development

Temporal 開發指南:掌握 Workflow as Code 打造穩定可靠的分散式流程系列 第 17

Day17 - Temporal 互動 API 的設計指南(Signal / Query / Update)

  • 分享至 

  • xImage
  •  

本篇聚焦「互動 API」:Signal、Query、Update,看如何透過 API 與有狀態且可重播的 Workflow 互動,達成流程的推進。
並提供對照表、範例與設計指南協助在不同情境下使用正確的 API。

1. Message Passing 簡介與對照表

簡介:

  • Signal
    • 作用:單向通知,將事件寫入 Event History,不回傳結果
    • 限制:不保證即時處理;不適用需要強回應/結果的情境
    • 適合情境:提醒/通知、觸發狀態轉換、外部事件到來
  • Query
    • 作用:只讀查詢當前 Workflow 狀態
    • 限制:不可修改狀態;不可阻塞等待外部事件;回傳即時快照
    • 適合情境:查詢進度、讀取內部狀態、查詢已完成的 Workflow
  • Update
    • 作用:互動式操作,Workflow 接受並回覆結果;可用 UpdateOptions 設定 wait stage(ACCEPTED/COMPLETED)與 updateId 冪等
    • 限制:相較 Signal/Query 成本較高,需要在 Workflow 端實作對應方法;大量使用可能放大 Event History
    • 適合情境:需要被受理與成功/失敗結果的動作,例如審核決策、狀態變更、記賬

Message Passing API 對照表

方法 類型 同步性 功能 輸入參數 回傳型別 適用情境
Query(typed) 物件 同步 讀取狀態,無副作用 stub.queryMethod(args...) T 查詢進度/狀態
Query(untyped) 物件 同步 以名稱字串查詢 stub.query("queryType", T.class, args...)TypeRef<T> T 跨程式/缺介面
Signal(typed) 物件 非同步 投遞事件,不保證即時回應 stub.signalMethod(args...) void 通知/觸發狀態更新
Signal(untyped) 物件 非同步 以名稱字串投遞 stub.signal("signalName", args...) void 跨程式/缺介面
SignalWithStart 物件 非同步 不存在則啟動並送 Signal;存在則直接送 Signal stub.signalWithStart(signalName, signalArgs[], startArgs[]) WorkflowExecution upsert 語意,避免重複建立
Update(typed) 物件 可選 強語意更新,保證回覆 stub.updateMethod(args...) Tvoid 要立即知道成功/失敗
Update(untyped, start) 物件 非同步 啟動更新並回傳 handle stub.startUpdate(UpdateOptions, args...) WorkflowUpdateHandle<T> 先發起,稍後再取結果
ExecuteUpdateWithStart 物件 可選 不存在則啟動並送 Update;可選擇是否等待結果 stub.executeUpdateWithStart(UpdateOptions, updateArgs[], startArgs[]) T upsert 並更新狀態
StartUpdateWithStart 物件 非同步 不存在則啟動並「啟動 Update」回傳 handle stub.startUpdateWithStart(UpdateOptions, updateArgs[], startArgs[]) WorkflowUpdateHandle<T> upsert 後稍後再取結果

2. 程式碼範例(typed / untyped)

2.1 Query

// typed
MyWorkflow stub = client.newWorkflowStub(MyWorkflow.class, options);
int count = stub.getPendingCount();

// untyped
WorkflowStub u = client.newUntypedWorkflowStub("MyWorkflow", options);
int count2 = u.query("getPendingCount", Integer.class);

2.2 Signal

// typed
MyWorkflow stub = client.newWorkflowStub(MyWorkflow.class, options);
stub.addItem("item-1");

// untyped(可跨程式/跨語言)
WorkflowStub u = client.newUntypedWorkflowStub("MyWorkflow", options);
u.signal("addItem", "item-1");

// SignalWithStart:若 workflow 不存在 → 啟動並送 signal;存在 → 直接送 signal
WorkflowExecution exec = u.signalWithStart(
    "addItem",
    new Object[] { "item-1" },      // signal args
    new Object[] { "wf-123" }       // start args(對應 @WorkflowMethod 參數)
);

2.3 Update

// typed(等待結果)
MyWorkflow stub = client.newWorkflowStub(MyWorkflow.class, options);
boolean ok = stub.approve("order-123");

// untyped(先發起再等:start)
WorkflowStub u = client.newUntypedWorkflowStub("MyWorkflow", options);
WorkflowUpdateHandle<Boolean> handle = u.startUpdate(
    UpdateOptions.newBuilder().setUpdateName("approve").build(),
    new Object[] { "order-123" }
);
Boolean ok3 = handle.getResult();

// ExecuteUpdateWithStart:若不存在 → 啟動並送 update;可選擇等待結果
Object result = u.executeUpdateWithStart(
    UpdateOptions.newBuilder().setUpdateName("approve").build(),
    new Object[] { "order-123" },   // update args
    new Object[] { "wf-123" }       // start args
);

3. 設計指南

  • API 選擇
    • 只投遞事件 → 用 Signal
    • 純讀取、無副作用 → 用 Query
    • 需被受理並回覆成功/失敗 → 用 Update(設定 UpdateOptions)
  • 是否需要 upsert
    • 不確定實例是否存在 → 用 SignalWithStart / ExecuteUpdateWithStart(設定明確 workflowId
  • typed 與 untyped
    • 可引用介面 → typed;需跨程式/跨語言或無介面 → untyped(名稱字串 / TypeRef)
  • 阻塞與等待策略
    • 需要同步結果 → Update 等待 COMPLETED 或 handle.getResult()
    • 非阻塞 → 等 ACCEPTED 或僅取得 handle,稍後再取結果
  • Workflow 狀態約束
    • 目標已完成 → 僅能 Query;Signal/Update 不適用
  • 冪等性
    • Update 設定 updateId;Signal/Query 規劃自然鍵避免重送歧義
  • 介面變更
    • 升級時保持相容或使用新名稱

結語

本篇重點在於了解互動過程的細節,讓流程可以順利可持久化的並完成一致性流程推進。

下一篇將進入 Entity Pattern Workflow 了解「每個 Entity 一個 Workflow」的實際操作。


上一篇
Day16 - Temporal 正確啟動流程的方式
下一篇
Day18 - Temporal Entity Pattern 的設計思維:讓每個商品庫存都有專屬 Workflow
系列文
Temporal 開發指南:掌握 Workflow as Code 打造穩定可靠的分散式流程21
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言