コンテンツにスキップ

メッセージキュー型の非同期処理から Temporal 移行へ

チェック

  • [ ] 本文を確認した
  • [ ] 概要を確認した
  • [ ] タグを確認した
  • [ ] inbox/ 直下へ移行した

概要

LayerXのマルチテナントバックエンドで、EventBridge、SQS、Worker、Connect RPCによる非同期処理基盤からTemporalへ移行する話。 同期APIと重い非同期処理のワークロード混在、状態永続化不足、リトライの自前実装を課題としている。 Temporal導入後の浸透策として、Protobufからのインフラコード生成、コンテキスト伝搬、Temporal向け認可トークンが扱われている。

本文

前提

対象は、複数のConnect RPCサーバーがドメインごとに稼働するマルチテナントバックエンド。 ドキュメント処理パイプラインやLLMを使った長時間処理など、重い非同期処理が日常的に存在する。

既存構成は EventBridge → SQS → Worker → Connect RPC。 通常のConnect RPCと同じ形で非同期処理を書ける利点はあるが、同期APIのレイテンシやスループットを非同期処理が悪化させる。 状態永続化がなく、途中再開やリトライロジックもアプリ側に寄る。

Temporal採用理由

  • 同期処理と非同期処理のワークロードを物理的に分離できる
  • Workflowの状態を永続化し、障害時に続きから再開できる
  • WorkerとTask Queueで処理の分散とスケールを担保できる
  • 実行状況、履歴、失敗リトライをWeb UIで追える

アーキテクチャ比較

検討案は大きく3つ。

  • 既存Workerを拡張し、SQS WorkerからTemporalを起動する
  • 各サービスから直接Workflowを起動する
  • EventBridge → Lambda → Temporalの構成にする

採用は EventBridge → Lambda → Temporal。 理由は、キュー基盤をTemporal Task Queueに一元化し、既存Workerの責務肥大化を避け、1イベントから複数Workflowを起動する責務やリトライをEventBridge/Lambda側で吸収できるため。 EventBridgeがバッファになり、Temporal障害が発火元へ直接波及しにくい点も利点。

浸透のための取り組み

Protobufからのインフラコード生成

Workflow / ActivityのGoコードは protoc-gen-go-temporal で生成。 protobuf optionを使い、ルーティングコードを生成する内製protoc pluginを用意して、SourceからTemporalまでつなげる。

コンテキスト伝搬

テナントID、リクエストID、分散トレース情報など、1リクエスト内で引き回したい横断情報はTemporal境界でそのまま渡らない。 GoではTemporal SDKの ContextPropagator を内製ライブラリで提供し、Client、Workflow、Activityの境界でHeader経由で受け渡す。 TypeScriptではSDKのInterceptorとAsyncLocalStorageを使って同様の伝搬を行う。

Temporal向け認可トークン

Workflowは中断・再開を許容する長寿命処理で、Activityは何度もリトライされ得る。 通常の短命な認可トークンをそのまま使えないため、StartWorkflow時にWorkflow専用の長寿命認可トークンへ引き換え、Activity内で再度通常の認可トークンに引き換える方式を取る。

要点

  • Temporal移行は「キュー置き換え」ではなく、状態永続化、可視性、リトライ、責務分離の設計変更。
  • EventBridge → Lambda → Temporalは、発火元を疎結合にしつつTemporal Task Queueへ責務を寄せる構成。
  • コンテキスト伝搬と認可トークンは、Temporalを実運用へ浸透させるための重要な周辺設計。

タグ

temporal #async-processing #eventbridge #protobuf #architecture #layerx