# 機能設計書 93-ワークフロー実行

## 概要

本ドキュメントは、Medusaコマースプラットフォームにおけるワークフロー実行機能の設計仕様を記述する。ワークフロー実行機能は、複数のステップで構成されるビジネスワークフローの実行・管理・監視を行う基盤を提供する。

### 本機能の処理概要

ワークフロー実行機能は、定義されたビジネスワークフローを実行し、各ステップの成功・失敗を管理する。トランザクション的な特性（コミット/ロールバック）を持ち、ステップ失敗時には補償処理（compensation）を実行して整合性を保つ。インメモリ実装とRedis実装の2つが提供されており、用途に応じて選択可能。

**業務上の目的・背景**：ECプラットフォームでは、注文処理、返品処理、在庫更新など、複数のシステム操作を一連のトランザクションとして実行する必要がある。例えば、注文作成では「在庫確保 → 支払い処理 → 注文レコード作成 → 通知送信」という一連のステップを実行し、途中で失敗した場合は既に実行されたステップを取り消す必要がある。ワークフロー実行機能により、このような複雑なビジネスロジックを宣言的に定義し、信頼性の高い実行を保証する。

**機能の利用シーン**：
- 注文作成ワークフローの実行（createOrderWorkflow）
- 返品処理ワークフローの実行（returnOrderWorkflow）
- 商品一括更新ワークフローの実行
- 非同期ステップを含む長時間実行ワークフロー
- 失敗したワークフローのリトライ

**主要な処理内容**：
1. ワークフローの実行開始（run）
2. ワークフロー実行状態の取得
3. ワークフロー実行一覧の取得・検索
4. ステップの成功/失敗登録
5. ステップのリトライ
6. ワークフローのキャンセル
7. ワークフロー完了時のイベント発行

**関連システム・外部連携**：
- PostgreSQL：ワークフロー実行履歴の永続化
- Redis：分散環境でのワークフロー状態管理（Redis実装の場合）
- イベントバス：ワークフロー完了時のイベント発行

**権限による制御**：ワークフロー実行自体には直接の権限制御は設けられていない。ワークフローを呼び出すAPI層で適切な認可チェックを行う。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 185 | ワークフロー実行一覧画面 | 主機能 | ワークフロー実行一覧の取得・表示 |
| 186 | ワークフロー実行詳細画面 | 主機能 | ワークフロー実行詳細の表示 |

## 機能種別

処理制御 / トランザクション管理

## 入力仕様

### 入力パラメータ（run）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| workflowIdOrWorkflow | string \| ReturnWorkflow | Yes | ワークフローIDまたはワークフロー定義 | 登録済みワークフローであること |
| options | WorkflowOrchestratorRunDTO | No | 実行オプション | - |
| options.input | T | No | ワークフローへの入力データ | ワークフロー定義による |
| options.transactionId | string | No | トランザクションID（指定しない場合は自動生成） | - |
| options.runId | string | No | 実行ID | - |
| options.resultFrom | string | No | 結果取得元のステップ名 | - |
| options.throwOnError | boolean | No | エラー時に例外をスローするか（デフォルト: true） | - |
| options.logOnError | boolean | No | エラー時にログ出力するか | - |
| options.context | Context | No | 実行コンテキスト | - |
| options.context.eventGroupId | string | No | イベントグループID | - |

### 入力パラメータ（listWorkflowExecutions）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| filters | FilterableWorkflowExecutionProps | No | フィルタ条件 | - |
| filters.q | string | No | テキスト検索（transaction_id, workflow_id, state, runId） | - |
| filters.workflow_id | string | No | ワークフローIDでフィルタ | - |
| filters.state | string | No | 状態でフィルタ | - |
| config | FindConfig | No | ページネーション・ソート設定 | - |

### 入力データソース

- APIルートハンドラーからの呼び出し
- サービス層からの直接呼び出し
- 他のワークフローからのサブワークフロー呼び出し

## 出力仕様

### 出力データ（run）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| acknowledgement | object | 実行確認情報 |
| acknowledgement.transactionId | string | トランザクションID |
| acknowledgement.workflowId | string | ワークフローID |
| acknowledgement.hasFinished | boolean | 完了したか |
| acknowledgement.hasFailed | boolean | 失敗したか |
| acknowledgement.parentStepIdempotencyKey | string | 親ステップのべき等キー |
| transaction | DistributedTransactionType | トランザクションオブジェクト |
| result | unknown | ワークフローの実行結果 |
| errors | object[] | エラー情報 |

### 出力データ（listWorkflowExecutions）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| - | WorkflowExecutionDTO[] | ワークフロー実行レコードの配列 |

### 出力先

- ワークフロー実行履歴：PostgreSQLデータベース
- ワークフロー状態：インメモリまたはRedis

## 処理フロー

### 処理シーケンス

```
1. ワークフロー取得
   └─ MedusaWorkflow.getWorkflow(workflowId)で定義を取得

2. トランザクションID生成
   └─ 指定がない場合は "auto-" + ulid() で自動生成

3. イベントハンドラー構築
   └─ buildWorkflowEvents()でライフサイクルイベントを設定

4. ワークフロー実行
   ├─ exportedWorkflow.run()を呼び出し
   ├─ 各ステップを順次実行
   └─ 失敗時は補償処理を実行

5. 完了判定
   ├─ hasFinished = transaction.hasFinished()
   └─ hasFailed = REVERTED または FAILED 状態か判定

6. 親ステップへの通知（サブワークフローの場合）
   └─ triggerParentStep()で親に成功/失敗を通知

7. 結果返却
   └─ acknowledgement と result を返却
```

### フローチャート

```mermaid
flowchart TD
    A[run呼び出し] --> B{ワークフロー存在?}
    B -->|No| C[MedusaError: NOT_FOUND]
    B -->|Yes| D[transactionId生成]
    D --> E[イベントハンドラー構築]
    E --> F[ワークフロー実行開始]
    F --> G[各ステップを順次実行]
    G --> H{ステップ成功?}
    H -->|Yes| I{次のステップあり?}
    I -->|Yes| G
    I -->|No| J[ワークフロー完了]
    H -->|No| K[補償処理実行]
    K --> L[ワークフロー失敗]
    J --> M{親ステップあり?}
    L --> M
    M -->|Yes| N[親ステップに通知]
    M -->|No| O[結果返却]
    N --> O
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-93-1 | ワークフロー存在確認 | 指定されたワークフローIDが登録されていない場合はNOT_FOUNDエラー | run()呼び出し時 |
| BR-93-2 | トランザクションID自動生成 | transactionIdが指定されない場合は "auto-{ulid}" 形式で自動生成 | run()呼び出し時 |
| BR-93-3 | サブワークフロー完了通知 | 親ワークフローから呼び出された場合、完了時に親ステップに成功/失敗を通知 | サブワークフロー完了時 |
| BR-93-4 | イベントグループID継承 | 同一eventGroupIdの場合、preventReleaseEventsをtrueに設定 | ネストされたワークフロー実行時 |
| BR-93-5 | キャンセル実行制限 | キャンセル対象のトランザクションが存在しない場合はエラー | cancel()呼び出し時 |

### 計算ロジック

テキスト検索フィルタの構築：
```typescript
// qパラメータが指定された場合
const textSearch = { $ilike: `%${q}%` }
const textSearchFilters = {
  $or: [
    { transaction_id: textSearch },
    { workflow_id: textSearch },
    { state: textSearch },
    { execution: { runId: textSearch } }
  ]
}
```

## データベース操作仕様

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| run | workflow_execution | INSERT | ワークフロー実行レコードの作成 |
| listWorkflowExecutions | workflow_execution | SELECT | 実行一覧の取得 |
| listAndCountWorkflowExecutions | workflow_execution | SELECT + COUNT | 実行一覧とカウントの取得 |

### テーブル別操作詳細

#### workflow_execution

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | id | ULID自動生成 | - |
| INSERT | workflow_id | ワークフローID | - |
| INSERT | transaction_id | トランザクションID | - |
| INSERT | state | TransactionState | INVOKING, DONE, FAILED等 |
| INSERT | execution | JSON | 実行詳細データ |
| SELECT | - | filters条件に基づく | qパラメータで全文検索可能 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| NOT_FOUND | MedusaError | ワークフローIDが未登録 | 正しいワークフローIDを指定 |
| - | Error | cancel時にトランザクションが存在しない | throwOnError=falseで実行 |
| - | StepError | ステップ内で例外発生 | 補償処理が自動実行される |

### リトライ仕様

- ステップ単位でのリトライが可能（retryStep）
- setStepSuccess/setStepFailureでステップの完了を明示的に設定可能
- 非同期ステップでは外部からの完了通知を待機

## トランザクション仕様

Sagaパターンによる分散トランザクション管理：
1. 各ステップは独立したトランザクションとして実行
2. ステップ失敗時は、成功済みステップの補償処理を逆順で実行
3. 補償処理もステップとして定義され、失敗した場合はログ記録

状態遷移：
- NOT_STARTED → INVOKING → DONE/FAILED
- FAILED → COMPENSATING → REVERTED/FAILED

## パフォーマンス要件

- ワークフロー実行開始：100ms以内
- ステップ実行：ステップ処理時間に依存
- 実行一覧取得：ページネーション適用時100ms以内

## セキュリティ考慮事項

- ワークフロー入力データのバリデーションはワークフロー定義側で実装
- 機密データを含むワークフローログは適切にマスキング
- 実行履歴へのアクセスは管理者権限を推奨

## 備考

- ワークフロー定義は@medusajs/framework/workflows-sdkで行う
- 非同期ステップはawaitStep()で一時停止し、外部からの完了通知を待つ
- WorkflowExecutionエンティティはMikroORMで管理

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

ワークフロー実行のデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | WorkflowExecution | `packages/modules/workflow-engine-inmemory/src/models/workflow-execution.ts` | ワークフロー実行エンティティの構造 |

**読解のコツ**: WorkflowExecutionエンティティは、workflow_id、transaction_id、state、executionなどのフィールドを持つ。stateはTransactionState型で、ワークフローの状態を表す。

#### Step 2: モジュールサービスを理解する

ワークフローモジュールのメインサービスを確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | workflows-module.ts | `packages/modules/workflow-engine-inmemory/src/services/workflows-module.ts` | WorkflowsModuleServiceの実装 |

**主要処理フロー**:
- **36-64行目**: クラス定義とDI（WorkflowOrchestratorServiceの注入）
- **66-73行目**: __hooksでアプリケーションライフサイクル管理
- **75-109行目**: prepareFilters()でテキスト検索フィルタを構築
- **137-195行目**: run()メソッドでワークフローを実行
- **210-231行目**: retryStep()でステップをリトライ
- **233-257行目**: setStepSuccess()でステップ成功を登録
- **259-285行目**: setStepFailure()でステップ失敗を登録

#### Step 3: オーケストレーターサービスを理解する

ワークフローの実際の実行ロジックを確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | workflow-orchestrator.ts | `packages/modules/workflow-engine-redis/src/services/workflow-orchestrator.ts` | WorkflowOrchestratorServiceの実装 |

**主要処理フロー**:
- **219-313行目**: run()メソッドでワークフローを実行
- **237-246行目**: ワークフローID必須チェック、エラー時はMedusaError
- **254-259行目**: ワークフロー定義取得、存在しない場合はエラー
- **265-273行目**: exportedWorkflow.run()でワークフロー実行
- **292-301行目**: 完了時にonFinishハンドラーを呼び出し
- **315-424行目**: cancel()メソッドでワークフローをキャンセル
- **663-706行目**: subscribe()でワークフローイベントを購読

### プログラム呼び出し階層図

```
WorkflowsModuleService
    │
    ├─ run(workflowIdOrWorkflow, options, context)
    │      ├─ context準備（eventGroupId, preventReleaseEvents）
    │      └─ workflowOrchestratorService_.run()
    │             ├─ MedusaWorkflow.getWorkflow(workflowId)
    │             ├─ buildWorkflowEvents()
    │             │      └─ ライフサイクルイベントハンドラー構築
    │             │             ├─ onBegin
    │             │             ├─ onStepBegin/Success/Failure
    │             │             ├─ onFinish
    │             │             └─ onTimeout
    │             │
    │             ├─ exportedWorkflow.run()
    │             │      └─ 各ステップを順次実行
    │             │
    │             └─ triggerParentStep() [サブワークフローの場合]
    │                    └─ setStepSuccess/Failure()
    │
    ├─ retryStep({ idempotencyKey, options })
    │      └─ workflowOrchestratorService_.retryStep()
    │
    ├─ setStepSuccess({ idempotencyKey, stepResponse })
    │      └─ workflowOrchestratorService_.setStepSuccess()
    │
    ├─ setStepFailure({ idempotencyKey, stepResponse })
    │      └─ workflowOrchestratorService_.setStepFailure()
    │
    ├─ cancel(workflowIdOrWorkflow, options)
    │      └─ workflowOrchestratorService_.cancel()
    │
    └─ listWorkflowExecutions(filters, config)
           ├─ prepareFilters()
           └─ super.listWorkflowExecutions()
```

### データフロー図

```
[入力]                           [処理]                           [出力]

run(workflowId, options)
    │
    ▼
MedusaWorkflow.getWorkflow() ───▶ ワークフロー定義
    │
    ▼
exportedWorkflow.run()
    │
    ├──▶ Step 1: invoke() ───▶ [成功] ───▶ result保存
    │         │
    │         └──▶ [失敗] ───▶ compensate() 開始
    │
    ├──▶ Step 2: invoke() ───▶ ...
    │
    └──▶ Step N: invoke() ───▶ [完了]
                                   │
                                   ▼
                              onFinish() ───▶ イベント発行
                                   │
                                   ▼
                              acknowledgement返却
                              {
                                transactionId,
                                workflowId,
                                hasFinished,
                                hasFailed
                              }
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| workflows-module.ts | `packages/modules/workflow-engine-inmemory/src/services/workflows-module.ts` | ソース | ワークフローモジュールサービス（インメモリ実装） |
| workflow-orchestrator.ts | `packages/modules/workflow-engine-redis/src/services/workflow-orchestrator.ts` | ソース | ワークフローオーケストレーター（Redis実装） |
| workflow-execution.ts | `packages/modules/workflow-engine-inmemory/src/models/workflow-execution.ts` | モデル | ワークフロー実行エンティティ |
| workflows-sdk | `packages/core/framework/src/workflows-sdk/` | ソース | ワークフロー定義SDK |
| core-flows | `packages/core/core-flows/` | ソース | 事前定義ワークフロー群 |
