iT邦幫忙

2025 iThome 鐵人賽

DAY 20
0
Software Development

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

Day20 - Asynchronous Activity Completion - 非同步完成,讓資源不再卡住

  • 分享至 

  • xImage
  •  

1. 為什麼需要 Asynchronous Activity Completion?

在現實系統中,常常會遇到這種「長尾」任務:

  • 等第三方金流回應(有時候還要好幾分鐘)
  • 等客服或使用者補件、回覆
  • 等一個慢到爆的外部系統處理完

如果直接用 Activity 來等,Worker 的執行續就會整個卡住,什麼事都不能做,浪費資源。

這時候就該用 非同步完成(Asynchronous Activity Completion)。

它的好處就是:

  • Worker 不用乾等,釋放掉這個 Activity 所需的資源,馬上就能回去跑其他任務。
  • 等外部系統或人工處理完,再把結果丟回來就好。
  • 同時具有 Temporal 超時、取消、重試的能力,免去自己寫一堆補償邏輯。

簡單來說,讓工人先去做其他的事情,結果晚點等別人補回來,讓整個流程穩定可靠的持續運行。

2. 程式碼範例

以下為核心用法。實際 API 以對應版本官方文件為準;範例聚焦關鍵步驟:取得 Token、宣告非同步完成、於外部完成。

2.1 Activity 實作

import io.temporal.activity.Activity;
import io.temporal.activity.ActivityExecutionContext;

public class MyActivitiesImpl implements MyActivities {
  @Override
// 由 Workflow 呼叫,傳入關聯 ID
  public String longWait(String correlationId) {
ActivityExecutionContext ctx = Activity.getExecutionContext(); // 取得執行脈絡
    // 取得 Task Token,代表這次 Activity 嘗試
    byte[] token = ctx.getTaskToken();

// 將 Token 與 correlationId 永續化(之後用於完成)
    persistToken(correlationId, token);

// 標記:此 Activity 不在回傳時完成
    ctx.doNotCompleteOnReturn();
    return "ignored"; // 回傳值會被忽略,之後改用 Token 回填真正結果
  }
}

2.2 外部回應非同步完成

import io.temporal.client.ActivityCompletionClient;
import io.temporal.client.WorkflowClient;

WorkflowClient wc = WorkflowClient.newInstance(service);

// 取得 ActivityCompletionClient 用於完成活動
ActivityCompletionClient acc = wc.newActivityCompletionClient();

byte[] token = loadToken(correlationId); // 依 correlationId 取回先前儲存的 Token
acc.complete(token, new Result("OK")); // 完成該次 Activity 嘗試並回傳結果
// 失敗:acc.completeExceptionally(token, ApplicationFailure.newFailure("fail", "ExternalError")); // 回報失敗
// 取消:acc.reportCancellation(token, details); // 回報取消(可含細節)
// 心跳:acc.heartbeat(token, progress); // 回報進度(如 0-100)

2.3 程式碼重點

  • 於 Activity 取得 Task Token,先儲存Token,再 doNotCompleteOnReturn()宣告「先不完成」。
  • 對外僅提供 correlationId,以它查回最新 Token。
  • 回傳結果:
    • 外部完成:ActivityCompletionClient.complete(token, result)
    • 外部失敗:completeExceptionally(token, failure)(可標記可/不可重試)。
    • 外部取消:reportCancellation(token, details)
    • 回報進度:heartbeat(token, progress),同時可感知取消。
  • 設定 ScheduleToCloseHeartbeatTimeout 管控上限與取消傳播。

3. 設計思維與常見陷阱

3.1 Token 的安全與儲存

  • Task Token 視為敏感憑證:僅在後端永續化(加密+TTL),對外以 correlationId 對應、不直接提供 Token
  • 重試時以 correlationId 覆蓋更新為最新 Token。

3.2 重試與超時策略

  • Activity 儲存 Token 失敗時直接拋錯交給 Temporal 重試
  • 外部完成呼叫失敗採指數退避重試
  • 設定 ScheduleToCloseHeartbeatTimeout 管控上限與取消
  • correlationId 作為冪等鍵。

3.3 Webhook

  1. Activity 產生 correlationId,儲存 correlationId → token
  2. 回傳 pending 並把 correlationId 傳給前端或第三方;
  3. 第三方完成後呼叫你的 webhook(帶 correlationId 和結果);
  4. 你的服務查回 Token → 呼叫 Completion API 完成該 Activity。

3.4 常見陷阱與解法(對照表)

常見陷阱 風險/影響 建議解法
直接把 Token 暴露給第三方 安全與誤用風險,可能被偽造完成/取消 Token 僅存於後端;對外只提供 correlationId;Webhook 簽章驗證/授權;最小權限與稽核
忽略取消 外部持續工作、成本浪費 實作 heartbeat-by-token 並檢查取消;外部收到取消即停止並回報取消;外部操作需冪等
觀測不足 難以發現卡單與 SLA 退化 建立指標(等待中數量、等待時間分布、完成/失敗/取消率)、加上 correlationId 日誌、設定警示與看板

結語

Asynchronous Activity Completion 讓 Activity 快速釋放 Worker 資源;讓外部服務完成任務時再回傳結果;確保整合活動維持高吞吐與可靠性。


上一篇
Day19 - Temporal Child Workflow:大型流程的治理模式
下一篇
Day21 - Temporal Cancel:設計能被中途喊停的流程
系列文
Temporal 開發指南:掌握 Workflow as Code 打造穩定可靠的分散式流程21
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言