
# 워크플로 기한

워크플로에 기한을 설정할 수 있습니다. 실행 중인 워크플로가 지정된 시간 안에 완료되지 않으면 Queuety이 실패로 표시하고 선택적으로 핸들러를 호출합니다. 일시 중지되었거나 신호 또는 다른 워크플로를 기다리는 워크플로는 대기 중에 만료되지 않습니다. 기한은 장시간 실행되는 `wp queuety work` 프로세스가 약 1분마다 확인하며, `--once` 작업자나 WP-Cron 대체 프로세스가 확인하지 않습니다. 이 기능은 무기한 실행되어서는 안 되는 장기 실행 워크플로를 위한 데드맨 스위치 역할을 합니다.

## 기한 설정

워크플로 빌더에서 `must_complete_within()`을 사용해 허용되는 최대 시간을 설정하세요. 기한을 초과했을 때 실행할 핸들러를 등록하려면 `on_deadline()`을 사용하세요.

```php
use Queuety\Queuety;

Queuety::workflow( 'data_import' )
    ->then( FetchDataHandler::class )
    ->then( TransformDataHandler::class )
    ->then( LoadDataHandler::class )
    ->must_complete_within( hours: 24 )
    ->on_deadline( ImportTimeoutHandler::class )
    ->dispatch( [ 'source' => $url ] );
```

`must_complete_within()` 메서드는 합산되는 이름 지정 매개변수를 받습니다.

```php
->must_complete_within( hours: 2, minutes: 30 )  // 2.5 hours
->must_complete_within( days: 1 )                 // 24 hours
->must_complete_within( seconds: 3600 )           // 1 hour
->must_complete_within( days: 1, hours: 12 )      // 36 hours
```

## 기한 핸들러

기한 `on_deadline()` 핸들러 클래스는 `handle( array $state ): void` 메서드를 구현해야 합니다. 이 메서드는 공개 워크플로 상태(`_`로 시작하지 않는 모든 키)를 받습니다.

```php
class ImportTimeoutHandler {

    public function handle( array $state ): void {
        // Alert the team.
        wp_mail(
            'ops@example.com',
            'Import workflow timed out',
            'Workflow for source ' . ( $state['source'] ?? 'unknown' ) . ' exceeded its deadline.'
        );

        // Clean up partial work.
        if ( isset( $state['temp_file'] ) ) {
            unlink( $state['temp_file'] );
        }
    }
}
```

기한 핸들러는 선택 사항입니다. 사용자 지정 로직 없이 워크플로만 실패시키려면 `on_deadline()` 없이 `must_complete_within()`을 사용하세요.

## 기한 확인 작동 방식

작업자는 처리 루프의 일부로 60초마다 만료된 기한을 확인합니다. `status`이 여전히 `running`이고 `deadline_at`가 과거인 워크플로를 찾으면, 등록된 경우 `on_deadline` 핸들러를 호출하고 오류 메시지 `Deadline exceeded`와 함께 워크플로를 실패로 표시한 뒤 `workflow_deadline_exceeded` 로그 이벤트를 기록합니다. 기한은 워크플로 행에 `deadline_at` 타임스탬프로 저장되며, 설정된 시간을 기준으로 디스패치 시점에 계산됩니다.

## 만료 시 동작

워크플로가 기한을 초과하면 상태가 `failed`로 바뀌고 오류 메시지는 `Deadline exceeded`로 설정됩니다. 등록된 경우 기한 핸들러가 동기적으로 실행되고 `workflow_deadline_exceeded` 로그 항목이 기록됩니다. 실행 중인 작업은 실행 도중 중단되지 않지만, 워크플로는 만료된 단계 경계를 넘어 진행하지 않습니다. 기한 핸들러 자체에서 예외가 발생하면 예외를 조용히 포착하고 워크플로는 계속 실패 상태가 됩니다.

## WorkflowBuilder 메서드

| 메서드 | 설명 |
|---|---|
| `must_complete_within( int $seconds = 0, int $minutes = 0, int $hours = 0, int $days = 0 )` | 허용되는 최대 시간을 설정합니다. 모든 매개변수가 합산됩니다. |
| `on_deadline( string $handler_class )` | 기한을 초과했을 때 호출할 핸들러를 등록합니다. |

## 예시: 재시도와 기한

기한 만료로 실패한 워크플로를 재시도하는 것은 대개 유용하지 않습니다. `retry_workflow()`은 워크플로를 `running`로 초기화하고 실패한 단계를 다시 큐에 넣지만, 기한을 지우거나 연장하지 않으므로 다음 기한 확인에서 약 1분 이내에 다시 실패합니다. 대신 새 워크플로를 디스패치하세요.

```php
$status = Queuety::workflow_status( $workflow_id );

if ( 'failed' === $status->status->value ) {
    // Check if it was a deadline failure.
    // You may want to dispatch a new workflow instead of retrying.
    Queuety::retry_workflow( $workflow_id );
}
```

## 기한과 대기 지연 비교

기한은 전체 워크플로 실행 시간에 적용됩니다. 대기 지연(`->delay()`)은 단계 순서의 일부로 워크플로를 정해진 시간 동안 일시 중지합니다. 1시간 대기 지연과 2시간 기한이 설정된 워크플로는 대기 단계를 제외한 단계의 총 실행 시간이 1시간을 넘으면 실패합니다.
