
# Кінцеві терміни робочих процесів

Для робочих процесів можна задати кінцевий термін. Якщо запущений робочий процес не завершиться протягом указаного часу, Queuety позначить його як невдалий і за потреби викличе обробник. Робочі процеси на паузі або в очікуванні сигналу чи інших робочих процесів не вважаються такими, що перевищили термін, поки очікують. Довготривалий процес `wp queuety work` перевіряє кінцеві терміни приблизно раз на хвилину, а не воркери `--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'] );
        }
    }
}
```

Обробник кінцевого терміну необов’язковий. Якщо потрібно лише позначити робочий процес як невдалий без виконання власної логіки, використовуйте `must_complete_within()` без `on_deadline()`.

## Як працює перевірка кінцевого терміну

Воркер перевіряє кінцеві терміни, що минули, кожні 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` і повторно додає крок із помилкою до черги, але не скидає і не продовжує кінцевий термін, тож наступна перевірка протягом приблизно хвилини знову завершить його помилкою. Натомість запустіть новий робочий процес.

```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()`) призупиняють робочий процес на визначений час як частину послідовності кроків. Якщо робочий процес має годинну затримку сну та кінцевий термін у 2 години, він завершиться помилкою, якщо кроки поза сном триватимуть загалом понад 1 годину.
