
# Časové limity workflow

Workflow lze nastavit časový limit. Pokud běžící workflow není dokončeno v určené době, Queuety jej označí jako neúspěšné a případně zavolá obslužnou rutinu. Běh workflow se neukončí, pokud je pozastavené nebo čeká na signál či jiná workflow. Časové limity kontroluje přibližně jednou za minutu dlouho běžící proces `wp queuety work`, nikoli pracovní procesy `--once` ani záložní mechanismus WP-Cron. Funguje to jako pojistka pro dlouho běžící workflow, která brání jejich nekonečnému běhu.

## Nastavení časového limitu

Pomocí `must_complete_within()` v builderu workflow nastavíte maximální povolenou dobu trvání. Pomocí `on_deadline()` zaregistrujete obslužnou rutinu, která se spustí při překročení časového limitu.

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

Metoda `must_complete_within()` přijímá pojmenované parametry, jejichž hodnoty se sčítají:

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

## Obslužná rutina časového limitu

Třída obslužné rutiny `on_deadline()` musí implementovat metodu `handle( array $state ): void`. Obdrží veřejný stav workflow (všechny klíče, které nezačínají na `_`).

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

Obslužná rutina časového limitu je volitelná. Pokud chcete, aby workflow pouze selhalo bez spuštění vlastního kódu, použijte `must_complete_within()` bez `on_deadline()`.

## Jak funguje kontrola časových limitů

Pracovní proces kontroluje překročené časové limity každých 60 sekund v rámci své zpracovatelské smyčky. Když najde workflow, jehož `status` je stále `running` a jehož `deadline_at` už uplynul, zavolá zaregistrovanou obslužnou rutinu `on_deadline`, označí workflow jako neúspěšné s chybovou zprávou `Deadline exceeded` a zaznamená událost `workflow_deadline_exceeded`. Samotný časový limit se ukládá jako časová značka `deadline_at` v řádku workflow a vypočítá se při spuštění workflow podle nakonfigurované doby trvání.

## Co se stane po vypršení časového limitu

Po překročení časového limitu se stav workflow změní na `failed`, chybová zpráva se nastaví na `Deadline exceeded`, případná obslužná rutina se spustí synchronně a zaznamená se položka protokolu `workflow_deadline_exceeded`. Běžící úlohy se uprostřed vykonávání nepřerušují, workflow ale nepokračuje za hranici kroku, při kterém časový limit vypršel. Pokud obslužná rutina časového limitu sama vyvolá výjimku, výjimka se tiše zachytí a workflow přesto skončí jako neúspěšné.

## Metody WorkflowBuilder

| Metoda | Popis |
|---|---|
| `must_complete_within( int $seconds = 0, int $minutes = 0, int $hours = 0, int $days = 0 )` | Nastaví maximální povolenou dobu trvání. Hodnoty všech parametrů se sčítají. |
| `on_deadline( string $handler_class )` | Zaregistruje obslužnou rutinu, která se zavolá při překročení časového limitu. |

## Příklad: časový limit s opakováním

Opakovat workflow, které selhalo kvůli časovému limitu, je zřídka užitečné. `retry_workflow()` obnoví jeho stav na `running` a znovu zařadí neúspěšný krok do fronty, nevymaže ani neprodlouží však časový limit, takže při další kontrole, přibližně za minutu, workflow znovu selže. Místo toho spusťte nové workflow.

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

## Časový limit a prodlevy spánku

Časový limit se vztahuje na celou dobu trvání workflow. Prodlevy spánku (`->delay()`) pozastaví workflow na pevně stanovenou dobu jako součást sekvence kroků. Workflow s prodlevou spánku v délce 1 hodiny a časovým limitem 2 hodiny selže, pokud kroky mimo spánek trvají celkem déle než 1 hodinu.
