前面的篇幅雖然啟動了三個流程,但剛接觸 Temporal 時,會很困惑「啟動方式很多,要選哪一個?」
本篇聚焦「啟動流程」,搭配對照表與極短範例,幫你迅速理解每種啟動方式的語意、是否同步、典型使用情境與常見陷阱,並提供簡單的決策指南協助選擇正確 API。
方法 | 類型 | 是否同步 | 功能 | 輸入參數 | 回傳型別 | 適用情境 | 常見陷阱 | 典型業務案例 |
---|---|---|---|---|---|---|---|---|
WorkflowClient.execute(...) | 靜態 | 可選(同步/非同步) | 啟動,回傳 CompletableFuture;等待才會阻塞 | Workflow stub method 參數 | CompletableFuture<T> |
有 typed stub,要一次拿結果 | 呼叫端被 block,長流程會卡住 | 一次性批次處理:產生報表並等待產出檔案 |
WorkflowClient.start(...) | 靜態 | 非同步 | 啟動但不等結果 | Workflow stub method 參數 | WorkflowExecution |
有 typed stub,只想非同步跑 | 忘記 getResult() → 沒人收結果 |
非同步寄信流程,結果可晚點查 |
Typed Stub method(...) | 物件 | 同步 | 直接呼叫 interface 方法即啟動 | Workflow 定義的方法參數 | T |
最常見用法,語意清楚 | workflowId 管理不當 → 重複啟動 | 新用戶註冊 → 建立帳號 workflow |
WorkflowStub.start(...) | 物件 | 非同步 | 以 untyped stub 啟動 Workflow | start 參數(無方法名) | WorkflowExecution |
只能透過動態呼叫,無法 import interface | 型別不安全,錯參數 runtime error | 跨模組啟動:BFF 層啟動 Workflow |
signalWithStart(...) | 物件 | 非同步 | Workflow 不存在 → 新啟動並送 Signal;已存在 → 直接送 Signal | signal 名稱, signal args, start args | WorkflowExecution |
不確定 Workflow 是否已存在 | workflowId 設錯 → 啟動多個流程 | 客服審核流程:使用者送出申訴 |
executeUpdateWithStart(...) | 物件 | 可選(同步/非同步) | Workflow 不存在 → 啟動並送 Update;可選擇等結果 | update 名稱, UpdateOptions , update args, start args |
T 或 WorkflowUpdateHandle<T> |
更新 Workflow 狀態但不確定是否存在 | Event History 膨脹、要注意 retry/timeout | 支付流程:若不存在 → 建立並更新付款狀態 |
首先連線 Server,並準備 Workflow 啟動選項:
// 建立與 Temporal 服務的用戶端(可重用、執行緒安全,建議應用程式生命週期內共用)
WorkflowClient client = WorkflowClient.newInstance(service);
// 建構 Workflow 啟動選項(Start 時使用)
WorkflowOptions options = WorkflowOptions.newBuilder()
// 指定 Task Queue,必須與對應 Worker 的 taskQueue 一致,否則拿不到任務
.setTaskQueue("user-task-queue")
// 指定此 Workflow 的唯一識別(建議使用穩定/自然鍵:例如 registration-{email})
// 可避免重複啟動;若相同 ID 已存在則預設會拒絕啟動
.setWorkflowId("registration-123")
// 完成建構,取得不可變的 WorkflowOptions
.build();
RegistrationWorkflow workflow = client.newWorkflowStub(RegistrationWorkflow.class, options);
CompletableFuture<Object> cf = WorkflowClient.execute(workflow::register, "alice@example.com");
Object result = cf.get();
RegistrationWorkflow workflow = client.newWorkflowStub(RegistrationWorkflow.class, options);
WorkflowExecution exec = WorkflowClient.start(workflow::register, "alice@example.com");
// 需要之後再取結果
String result = WorkflowStub.fromTyped(workflow).getResult(String.class);
RegistrationWorkflow workflow = client.newWorkflowStub(RegistrationWorkflow.class, options);
String result = workflow.register("alice@example.com");
RegistrationWorkflow typed = client.newWorkflowStub(RegistrationWorkflow.class, options);
WorkflowStub dynamic = WorkflowStub.fromTyped(typed);
WorkflowExecution exec = dynamic.start("alice@example.com");
// 若無法引用 Workflow 介面,可直接以 Workflow Type 建立 untyped stub
WorkflowStub untyped = client.newUntypedWorkflowStub("RegistrationWorkflow", options);
WorkflowExecution exec2 = untyped.start("alice@example.com");
註:Workflow Type 字串需與 Worker 所註冊的 Workflow type 一致。直接建立的 untyped stub 與 fromTyped(...)
取得的效果相同,差異在於前者不依賴介面,後者可沿用 typed stub 的 options 與識別設定。
跨程式/跨語言使用:用戶端只需能連到 Temporal Server,即可跨進程或微服務啟動目標 Workflow。此時常見做法是使用 newUntypedWorkflowStub("<WorkflowType>", options)
啟動,並以名稱字串呼叫 signal(...)
/query(...)
/executeUpdate(...)
;確保 workflowType
、taskQueue
、workflowId
與資料序列化(DataConverter,例如 JSON/Protobuf)在不同程式間對齊即可。
RegistrationWorkflow typed = client.newWorkflowStub(RegistrationWorkflow.class, options);
WorkflowStub dynamic = WorkflowStub.fromTyped(typed);
WorkflowExecution exec = dynamic.signalWithStart(
"signalMethodName", // signal 名稱
new Object[] { "ticket-001", "內容" }, // signal 參數
new Object[] { "alice@example.com" } // start 參數
);
RegistrationWorkflow typed = client.newWorkflowStub(RegistrationWorkflow.class, options);
WorkflowStub dynamic = WorkflowStub.fromTyped(typed);
Object o = dynamic.executeUpdateWithStart(
UpdateOptions.newBuilder().setUpdateName("update").build(), // UpdateOptions
new Object[] { "order-123", 1000 }, // update 參數
new Object[] { "order-123" } // start 參數(預設 Workflow 方法)
);
updateId
使用自然鍵,如 recordPayment-{orderId}-{attempt}
,兼顧可讀與冪等。先回答三個問題,就能快速選 API:
WorkflowClient.execute(...)
或 Typed Stub method(...)
WorkflowClient.start(...)
+ WorkflowStub.getResult(...)
或 WorkflowStub.start(...)
signalWithStart(...)
或 executeUpdateWithStart(...)
WorkflowStub.start(...)
;否則用 Typed Stub 直接呼叫常見反模式:
execute(...)
導致呼叫端阻塞order-{orderId}
、registration-{emailHash}
workflowId
導向同一個 Workflow 避免重複啟動signalWithStart(...)
/executeUpdateWithStart(...)
可實作 upsert:存在則訊息或更新,不在則啟動本篇整理了 6 種 Workflow 啟動方式,並以「是否同步」輔助選擇,搭配精簡範例與決策指引,協助選對 API。
下一篇將進入 Message Passing:介紹 Signal、Query、Update,串起從「啟動 → 互動」的完整設計。