# workflow-orchestration-patterns > 分散システムのためのTemporalを使用した耐久性のあるワークフローを設計します。ワークフローとアクティビティの分離、Sagaパターン、状態管理、および決定論の制約をカバーします。長時間実行プロセス、分散トランザクション、またはマイクロサービスオーケストレーションを構築する際に使用します。 - Author: amurata - Repository: amurata/cc-tools - Version: 20251128195350 - Stars: 5 - Forks: 0 - Last Updated: 2026-02-06 - Source: https://github.com/amurata/cc-tools - Web: https://mule.run/skillshub/@@amurata/cc-tools~workflow-orchestration-patterns:20251128195350 --- > **[English](../../../../../plugins/backend-development/skills/workflow-orchestration-patterns/SKILL.md)** | **日本語** --- name: workflow-orchestration-patterns description: 分散システムのためのTemporalを使用した耐久性のあるワークフローを設計します。ワークフローとアクティビティの分離、Sagaパターン、状態管理、および決定論の制約をカバーします。長時間実行プロセス、分散トランザクション、またはマイクロサービスオーケストレーションを構築する際に使用します。 --- # ワークフローオーケストレーションパターン 基本的な設計上の決定、レジリエンスパターン、および信頼性の高い分散システムを構築するためのベストプラクティスをカバーする、Temporalを使用したワークフローオーケストレーションアーキテクチャをマスターします。 ## ワークフローオーケストレーションをいつ使用するか ### 理想的なユースケース (出典: docs.temporal.io) - マシン/サービス/データベースにまたがる**マルチステッププロセス** - オールオアナッシングのセマンティクスを必要とする**分散トランザクション** - 自動的な状態永続化を伴う**長時間実行ワークフロー**(数時間から数年) - 最後に成功したステップから再開する必要がある**障害回復** - **ビジネスプロセス**: 予約、注文、キャンペーン、承認 - **エンティティライフサイクル管理**: 在庫追跡、アカウント管理、カートワークフロー - **インフラストラクチャ自動化**: CI/CDパイプライン、プロビジョニング、デプロイメント - タイムアウトとエスカレーションを必要とする**人間参加型**システム ### 使用すべきでない場合 - 単純なCRUD操作(直接API呼び出しを使用) - 純粋なデータ処理パイプライン(Airflow、バッチ処理を使用) - ステートレスなリクエスト/レスポンス(標準APIを使用) - リアルタイムストリーミング(Kafka、イベントプロセッサを使用) ## 重要な設計上の決定: ワークフロー vs アクティビティ **基本ルール** (出典: temporal.io/blog/workflow-engine-principles): - **ワークフロー** = オーケストレーションロジックと意思決定 - **アクティビティ** = 外部相互作用(API、データベース、ネットワーク呼び出し) ### ワークフロー (オーケストレーション) **特徴:** - ビジネスロジックと調整を含む - **決定論的でなければならない**(同じ入力 → 同じ出力) - 直接的な外部呼び出しは**できない** - 障害が発生しても状態は自動的に保存される - インフラストラクチャの障害にもかかわらず数年間実行可能 **ワークフロータスクの例:** - 実行するステップの決定 - 補償ロジックの処理 - タイムアウトとリトライの管理 - 子ワークフローの調整 ### アクティビティ (外部相互作用) **特徴:** - すべての外部システム相互作用を処理する - 非決定論的であってもよい(API呼び出し、DB書き込み) - 組み込みのタイムアウトとリトライロジックを含む - **冪等でなければならない**(N回呼び出す = 1回呼び出す) - 短命(通常は数秒から数分) **アクティビティタスクの例:** - 支払いゲートウェイAPIの呼び出し - データベースへの書き込み - メールまたは通知の送信 - 外部サービスのクエリ ### 設計決定フレームワーク ``` 外部システムに触れるか? → アクティビティ オーケストレーション/意思決定ロジックか? → ワークフロー ``` ## コアワークフローパターン ### 1. 補償を伴うSagaパターン **目的**: ロールバック機能を持つ分散トランザクションを実装する **パターン** (出典: temporal.io/blog/compensating-actions-part-of-a-complete-breakfast-with-sagas): ``` 各ステップについて: 1. 実行前に補償を登録する 2. ステップを実行する(アクティビティ経由) 3. 失敗した場合、すべての補償を逆順(LIFO)で実行する ``` **例: 支払いワークフロー** 1. 在庫の確保(補償: 在庫の解放) 2. 支払いの請求(補償: 支払いの返金) 3. 注文の履行(補償: 履行のキャンセル) **重要な要件:** - 補償は冪等でなければならない - ステップを実行する前に補償を登録する - 補償を逆順で実行する - 部分的な失敗を適切に処理する ### 2. エンティティワークフロー(アクターモデル) **目的**: 単一のエンティティインスタンスを表す長寿命ワークフロー **パターン** (出典: docs.temporal.io/evaluate/use-cases-design-patterns): - 1つのワークフロー実行 = 1つのエンティティ(カート、アカウント、在庫アイテム) - ワークフローはエンティティの寿命の間持続する - 状態変更のためのシグナルを受け取る - 現在の状態に対するクエリをサポートする **使用例:** - ショッピングカート(アイテム追加、チェックアウト、有効期限) - 銀行口座(入金、出金、残高確認) - 製品在庫(在庫更新、予約) **利点:** - エンティティの振る舞いをカプセル化する - エンティティごとの一貫性を保証する - 自然なイベントソーシング ### 3. ファンアウト/ファンイン(並列実行) **目的**: 複数のタスクを並列に実行し、結果を集約する **パターン:** - 子ワークフローまたは並列アクティビティを生成する - すべての完了を待つ - 結果を集約する - 部分的な失敗を処理する **スケーリングルール** (出典: temporal.io/blog/workflow-engine-principles): - 個々のワークフローをスケーリングしない - 100万タスクの場合: 1000個の子ワークフロー × 各1000タスクを生成する - 各ワークフローを制限内に保つ ### 4. 非同期コールバックパターン **目的**: 外部イベントまたは人間の承認を待つ **パターン:** - ワークフローがリクエストを送信し、シグナルを待つ - 外部システムが非同期に処理する - ワークフローを再開するためのシグナルを送信する - ワークフローがレスポンスとともに継続する **使用例:** - 人間の承認ワークフロー - Webhookコールバック - 長時間実行される外部プロセス ## 状態管理と決定論 ### 自動的な状態保存 **Temporalの仕組み** (出典: docs.temporal.io/workflows): - 完全なプログラム状態が自動的に保存される - イベント履歴がすべてのコマンドとイベントを記録する - クラッシュからのシームレスな回復 - アプリケーションは障害前の状態を復元する ### 決定論の制約 **ワークフローはステートマシンとして実行される**: - リプレイ動作は一貫していなければならない - 同じ入力 → 毎回同じ出力 **ワークフローで禁止されていること** (出典: docs.temporal.io/workflows): - ❌ スレッド、ロック、同期プリミティブ - ❌ 乱数生成 (`random()`) - ❌ グローバル状態または静的変数 - ❌ システム時刻 (`datetime.now()`) - ❌ 直接的なファイルI/Oまたはネットワーク呼び出し - ❌ 非決定論的なライブラリ **ワークフローで許可されていること**: - ✅ `workflow.now()` (決定論的な時間) - ✅ `workflow.random()` (決定論的な乱数) - ✅ 純粋関数と計算 - ✅ アクティビティの呼び出し(非決定論的な操作) ### バージョニング戦略 **課題**: 古い実行がまだ実行されている間にワークフローコードを変更する **解決策**: 1. **バージョニングAPI**: 安全な変更のために `workflow.get_version()` を使用する 2. **新しいワークフロータイプ**: 新しいワークフローを作成し、新しい実行をそれにルーティングする 3. **後方互換性**: 古いイベントが正しくリプレイされることを確認する ## レジリエンスとエラー処理 ### リトライポリシー **デフォルトの動作**: Temporalはアクティビティを永遠にリトライする **リトライ構成**: - 初回リトライ間隔 - バックオフ係数(指数バックオフ) - 最大間隔(リトライ遅延の上限) - 最大試行回数(最終的に失敗する) **再試行不可能なエラー**: - 無効な入力(検証失敗) - ビジネスルール違反 - 永続的な障害(リソースが見つからない) ### 冪等性の要件 **なぜ重要か** (出典: docs.temporal.io/activities): - アクティビティは複数回実行される可能性がある - ネットワーク障害がリトライをトリガーする - 重複実行は安全でなければならない **実装戦略**: - 冪等性キー(重複排除) - 一意性制約によるチェック・ゼン・アクト - 挿入の代わりにアップサート操作 - 処理済みリクエストIDの追跡 ### アクティビティハートビート **目的**: 停止した長時間実行アクティビティを検出する **パターン**: - アクティビティが定期的なハートビートを送信する - 進捗情報を含める - ハートビートが受信されない場合はタイムアウト - 進捗ベースのリトライを有効にする ## ベストプラクティス ### ワークフロー設計 1. **ワークフローを焦点を絞ったものにする** - ワークフローごとに単一の責任 2. **小さなワークフロー** - スケーラビリティのために子ワークフローを使用する 3. **明確な境界** - ワークフローが調整し、アクティビティが実行する 4. **ローカルでテスト** - タイムスキップテスト環境を使用する ### アクティビティ設計 1. **冪等な操作** - リトライしても安全 2. **短命** - 数時間ではなく、数秒から数分 3. **タイムアウト構成** - 常にタイムアウトを設定する 4. **長いタスクのハートビート** - 進捗を報告する 5. **エラー処理** - リトライ可能とリトライ不可能を区別する ### 一般的な落とし穴 **ワークフロー違反**: - `workflow.now()` の代わりに `datetime.now()` を使用する - ワークフローコード内でのスレッドまたは非同期操作 - ワークフローから外部APIを直接呼び出す - ワークフロー内の非決定論的ロジック **アクティビティの間違い**: - 非冪等な操作(リトライを処理できない) - タイムアウトの欠落(アクティビティが永遠に実行される) - エラー分類なし(検証エラーをリトライする) - ペイロード制限(引数あたり2MB)の無視 ### 運用上の考慮事項 **モニタリング**: - ワークフロー実行時間 - アクティビティ失敗率 - リトライ試行とバックオフ - 保留中のワークフロー数 **スケーラビリティ**: - ワーカーによる水平スケーリング - タスクキューのパーティショニング - 子ワークフロー分解 - 適切な場合のアクティビティバッチ処理 ## 追加リソース **公式ドキュメント**: - Temporal コアコンセプト: docs.temporal.io/workflows - ワークフローパターン: docs.temporal.io/evaluate/use-cases-design-patterns - ベストプラクティス: docs.temporal.io/develop/best-practices - Saga パターン: temporal.io/blog/saga-pattern-made-easy **重要な原則**: 1. ワークフロー = オーケストレーション、アクティビティ = 外部呼び出し 2. 決定論はワークフローにとって交渉の余地なし 3. 冪等性はアクティビティにとって重要 4. 状態保存は自動的 5. 障害と回復を考慮して設計する