
# 워크플로 실행

워크플로는 단계 중 하나로 자식 워크플로를 시작할 수 있습니다. 부모 워크플로는 자식 워크플로 실행이 완료될 때까지 일시 중지된 다음, 자식의 최종 상태를 부모 상태에 병합합니다.

## `->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()` 메서드는 인수 두 개를 받습니다:
1. 워크플로 실행의 이름
2. 워크플로 실행의 단계를 정의하는 `WorkflowBuilder` 인스턴스

## 작동 방식

부모 워크플로가 `run_workflow` 단계에 도달하면:

1. 워크플로 실행이 자체 ID를 가진 독립 워크플로로 디스패치됩니다.
2. 부모 워크플로가 일시 중지됩니다.
3. 워크플로 실행이 평소처럼 단계를 진행합니다.
4. 워크플로 실행이 완료되면 최종 상태가 부모 상태에 병합됩니다.
5. 부모 워크플로가 다음 단계부터 다시 진행합니다.

## 부모/자식 상태

워크플로 실행은 부모의 현재 누적 상태를 초기 페이로드로 받습니다. 따라서 자식 단계는 이전 부모 단계에서 생성된 모든 데이터에 액세스할 수 있습니다:

```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 [];
    }
}
```

## 상태 병합

워크플로 실행이 완료되면 최종 상태에서 `_steps`, `_queue`, `_priority`, `_max_attempts` 같은 내부 키를 제외한 나머지가 부모 상태에 병합됩니다. 다음 부모 단계는 부모의 앞선 단계와 워크플로 실행 양쪽에서 나온 모든 데이터를 확인할 수 있습니다:

```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 [];
    }
}
```

## 워크플로 실행 옵션

워크플로 실행 빌더의 `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 );
```

## 중첩 워크플로 실행

워크플로 실행 자체에도 워크플로 실행을 포함할 수 있어 원하는 만큼 중첩할 수 있습니다:

```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 );
```
