
# ワークフローの依存関係

あるトップレベルのワークフローを、他のワークフローが完了した後にのみ続行させる場合は、ワークフロー依存関係の待機を使います。すべてを1つの巨大なワークフロー定義に押し込むことなく、ワークフロー間の連携を実現できます。

こうした待機は[非同期ハンドオフ](https://queuety.inline0.dev/ja/docs/workflows/async-handoffs)と特に相性がよく、1つのワークフローで独立した子ワークフローを開始してから、後でそれらの完了を待てます。

プランナーと実行役の詳しい例については、[エージェントオーケストレーション](https://queuety.inline0.dev/ja/docs/workflows/agent-orchestration)をご覧ください。

Queuetyには、次の3つのビルダーメソッドがあります:

- 1つのワークフローを対象とする`wait_for_workflow()`
- 複数のワークフローを対象とし、`all`、`any`、または`quorum`のセマンティクスを指定する`wait_for_workflows()`
- ワークフローIDが以前に開始したグループから取得される場合に使う`wait_for_workflow_group()`

## 1つのワークフローを待つ

```php
$research_id = Queuety::workflow( 'research_run' )
    ->then( PlanResearchStep::class )
    ->for_each( 'tasks', ExecuteResearchTask::class, 'results' )
    ->dispatch( [ 'brief_id' => 42 ] );

$editorial_id = Queuety::workflow( 'editorial_run' )
    ->wait_for_workflow( $research_id, 'research' )
    ->then( DraftBriefStep::class )
    ->dispatch();
```

`research_run`が完了すると、`editorial_run`が再開します。`result_key`を設定すると、完了した依存ワークフローの状態はそのキーの下に保存されます:

```php
$state['research']; // public state from the completed research workflow
```

`result_key`を指定しない場合、依存ワークフローの公開状態は、待機中のワークフローのトップレベル状態にマージされます。

## 複数のワークフローを待つ

```php
use Queuety\Enums\WaitMode;

Queuety::workflow( 'synthesis_run' )
    ->wait_for_workflows(
        [ $research_id, $editorial_id, $legal_id ],
        WaitMode::All,
        'dependencies'
    )
    ->then( PublishPacketStep::class )
    ->dispatch();
```

- `WaitMode::All`は、リスト内のすべてのワークフローが完了したときにのみ再開します。
- `WaitMode::Any`は、リスト内の最初のワークフローが完了したときに再開します。
- `WaitMode::Quorum`は、必要な数のワークフローが正常に完了した時点で再開します。

```php
Queuety::workflow( 'synthesis_run' )
    ->wait_for_workflows(
        [ $research_id, $editorial_id, $legal_id ],
        WaitMode::Quorum,
        'dependencies',
        quorum: 2,
    )
    ->then( PublishPacketStep::class )
    ->dispatch();
```

`result_key`を指定すると、複数のワークフローを待つ場合、完了した依存ワークフローの状態はワークフローIDをキーとして保存されます:

```php
[
    '42' => [ 'summary' => '...' ],
    '43' => [ 'summary' => '...' ],
]
```

`result_key`を指定しない場合、完了した依存ワークフローの状態は、依存関係の順に待機中のワークフローのトップレベル状態へマージされます。

## ワークフローの状態から依存IDを解決する

依存ワークフローのリストは、実行時まで確定せず、公開状態からワークフローIDを読み取るようにできます:

```php
Queuety::workflow( 'agent_follow_up' )
    ->wait_for_workflow( 'parent_workflow_id', 'parent' )
    ->then( FinalizeAgentRunStep::class )
    ->dispatch( [ 'parent_workflow_id' => $workflow_id ] );
```

複数の依存関係の場合:

```php
Queuety::workflow( 'aggregator' )
    ->wait_for_workflows( 'dependency_ids', WaitMode::Any, 'winner' )
    ->dispatch( [ 'dependency_ids' => [ 12, 18, 22 ] ] );
```

## 開始済みのワークフローグループを待つ

以前の`start_workflows()`または`start_agents()`ステップで永続的なグループキーを保存している場合は、公開状態を介してワークフローIDを受け渡さずに、そのグループを直接待てます。

```php
Queuety::workflow( 'brief_research' )
    ->then( PlanTopicsStep::class )
    ->start_agents( 'agent_tasks', $agent_run, group_key: 'researchers' )
    ->wait_for_agent_group( 'researchers', WaitMode::Quorum, 2, 'agent_results' )
    ->then( SynthesizeBriefStep::class )
    ->dispatch();
```

## 待機中の動作

ワークフローがこれらのステップのいずれかに到達すると、ステータスが`waiting_for_workflows`に変わります。待機中にワーカーがそのワークフローに割り当てられたままになることはありません。

```php
$state = Queuety::workflow_status( $workflow_id );
echo $state->status->value; // 'waiting_for_workflows'
echo $state->wait_type;     // 'workflow'
print_r( $state->waiting_for ); // ['42', '43']
```

待機ステップに到達する前に依存ワークフローがすでに完了している場合、ワークフローは直ちに続行します。

## 失敗時の動作

ワークフロー依存関係の待機は、成功を基準とします:

- `wait_for_workflow()`と`WaitMode::All`は、必須の依存ワークフローが1つでも失敗またはキャンセルされると失敗します。
- `WaitMode::Any`は、すべての依存ワークフローが終端状態に達し、成功したものが1つもない場合にのみ失敗します。
- `WaitMode::Quorum`は、残りの実行中ワークフローでは必要な定足数を満たせなくなった場合に失敗します。

この仕組みにより、1つのワークフローがタスクごとに`all`でき、別のワークフローがその結果、または最初に完了した成功分岐を待てる、プランナーと実行役のシステムでワークフローの待機が役立ちます。
