
# ワークフローの実行

ワークフローでは、ステップの1つとして子ワークフローを開始できます。親はrun-workflowが完了するまで一時停止し、その後、子の最終状態を親の状態にマージします。

## `->run_workflow()`メソッド

```php
use Queuety\Queuety;

$enrichment = Queuety::workflow( 'enrich_user' )
    ->then( FetchSocialHandler::class )
    ->then( FetchCreditScoreHandler::class );

Queuety::workflow( 'onboarding' )
    ->then( CreateAccountHandler::class )
    ->run_workflow( 'enrich_user', $enrichment )
    ->then( SendWelcomeEmailHandler::class )
    ->dispatch( [ 'email' => 'user@example.com' ] );
```

`run_workflow()`メソッドは2つの引数を取ります。
1. run-workflowの名前
2. run-workflowのステップを定義する`WorkflowBuilder`インスタンス

## 仕組み

親ワークフローが`run_workflow`ステップに到達すると、次の処理が行われます。

1. run-workflowは独自のIDを持つ独立したワークフローとしてディスパッチされます
2. 親ワークフローが一時停止します
3. run-workflowが通常どおり各ステップを実行します
4. run-workflowが完了すると、最終状態が親の状態にマージされます
5. 親ワークフローが次のステップから再開します

## 親子間の状態

run-workflowは、親の現在の累積状態を初期ペイロードとして受け取ります。そのため、子のステップから、それ以前の親ステップが生成したデータにアクセスできます。

```php
class CreateAccountHandler implements Step {
    public function handle( array $state ): array {
        $user_id = wp_create_user( $state['email'], wp_generate_password() );
        return [ 'user_id' => $user_id ];
    }

    public function config(): array {
        return [];
    }
}

// This run-workflow step can access 'user_id' from the parent
class FetchSocialHandler implements Step {
    public function handle( array $state ): array {
        $profile = fetch_social_profile( $state['user_id'] );
        return [ 'social_data' => $profile ];
    }

    public function config(): array {
        return [];
    }
}
```

## 状態のマージ

run-workflowが完了すると、最終状態（`_steps`、`_queue`、`_priority`、`_max_attempts`のような内部キーを除く）が親の状態にマージされます。次の親ステップでは、親の前のステップとrun-workflowの両方のデータを参照できます。

```php
class SendWelcomeEmailHandler implements Step {
    public function handle( array $state ): array {
        // Has access to:
        // - $state['email'] (from initial dispatch)
        // - $state['user_id'] (from CreateAccountHandler)
        // - $state['social_data'] (from run-workflow's FetchSocialHandler)
        // - $state['credit_score'] (from run-workflow's FetchCreditScoreHandler)

        send_welcome_email( $state['email'], $state['social_data'] );
        return [ 'welcome_sent' => true ];
    }

    public function config(): array {
        return [];
    }
}
```

## run-workflowのオプション

run-workflowビルダーの`on_queue()`、`with_priority()`、`max_attempts()`は子ワークフローに適用されます。`on_cancel()`、`prune_state_after()`、`must_complete_within()`、`version()`、`idempotency_key()`、`max_*()`の予算、`compensate_on_failure()`など、子ビルダーのその他のワークフローレベルのオプションは引き継がれません。

```php
$sub = Queuety::workflow( 'heavy_processing' )
    ->on_queue( 'background' )
    ->with_priority( Priority::Normal )
    ->max_attempts( 5 )
    ->then( StepA::class )
    ->then( StepB::class );

Queuety::workflow( 'parent' )
    ->run_workflow( 'heavy', $sub )
    ->then( FinalStep::class )
    ->dispatch( $payload );
```

## ネストしたrun-workflow

run-workflowにはさらにrun-workflowを含めることができ、任意の深さでネストできます。

```php
$inner = Queuety::workflow( 'inner' )
    ->then( InnerStepA::class )
    ->then( InnerStepB::class );

$middle = Queuety::workflow( 'middle' )
    ->then( MiddleStepA::class )
    ->run_workflow( 'inner', $inner )
    ->then( MiddleStepB::class );

Queuety::workflow( 'outer' )
    ->then( OuterStepA::class )
    ->run_workflow( 'middle', $middle )
    ->then( OuterStepB::class )
    ->dispatch( $payload );
```
