
# Workflow-Fristen

Für Workflows kann eine Frist festgelegt werden. Wenn ein laufender Workflow nicht innerhalb der vorgegebenen Dauer abgeschlossen wird, markiert Queuety ihn als fehlgeschlagen und ruft optional einen Handler auf. Während sie pausiert sind oder auf ein Signal oder andere Workflows warten, laufen die Fristen für Workflows nicht ab. Ein lang laufender `wp queuety work`-Prozess prüft etwa einmal pro Minute die Fristen, nicht die Worker `--once` oder der WP-Cron-Fallback. So fungiert die Frist als Sicherheitsmechanismus für lang laufende Workflows, die nicht unbegrenzt laufen sollen.

## Eine Frist festlegen

Verwende `must_complete_within()` im Workflow-Builder, um die maximal zulässige Dauer festzulegen. Mit `on_deadline()` registrierst du einen Handler, der bei Überschreitung der Frist ausgeführt wird.

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

Die Methode `must_complete_within()` akzeptiert benannte Parameter, die addiert werden:

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

## Fristenhandler

Die Handler-Klasse für Fristen `on_deadline()` muss eine `handle( array $state ): void`-Methode implementieren. Sie erhält den öffentlichen Workflow-Zustand (alle Schlüssel, die nicht mit `_` beginnen).

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

Der Fristenhandler ist optional. Wenn der Workflow nur fehlschlagen soll, ohne benutzerdefinierte Logik auszuführen, verwende `must_complete_within()` ohne `on_deadline()`.

## So funktioniert die Fristenprüfung

Der Worker prüft in seiner Verarbeitungsschleife alle 60 Sekunden auf abgelaufene Fristen. Findet er einen Workflow, dessen `status` weiterhin `running` ist und dessen `deadline_at` in der Vergangenheit liegt, ruft er den Handler `on_deadline` auf, sofern einer registriert ist, markiert den Workflow mit der Fehlermeldung `Deadline exceeded` als fehlgeschlagen und protokolliert ein Ereignis vom Typ `workflow_deadline_exceeded`. Die Frist selbst wird als Zeitstempel `deadline_at` in der Workflow-Zeile gespeichert und beim Start anhand der konfigurierten Dauer berechnet.

## Was beim Fristablauf geschieht

Wenn ein Workflow seine Frist überschreitet, ändert sich sein Status zu `failed`, die Fehlermeldung wird auf `Deadline exceeded` gesetzt, der Fristen-Handler wird synchron ausgeführt, sofern einer registriert ist, und es wird ein `workflow_deadline_exceeded`-Protokolleintrag erfasst. Laufende Jobs werden nicht mitten in der Ausführung unterbrochen, aber der Workflow wird nicht über die abgelaufene Schrittgrenze hinaus fortgesetzt. Löst der Fristen-Handler selbst eine Ausnahme aus, wird diese stillschweigend abgefangen und der Workflow endet trotzdem im Fehlerstatus.

## WorkflowBuilder-Methoden

| Methode | Beschreibung |
|---|---|
| `must_complete_within( int $seconds = 0, int $minutes = 0, int $hours = 0, int $days = 0 )` | Legt die maximal zulässige Dauer fest. Alle Parameter werden addiert. |
| `on_deadline( string $handler_class )` | Registriert einen Handler, der aufgerufen wird, wenn die Frist überschritten ist. |

## Beispiel: Frist mit Wiederholung

Einen Workflow erneut auszuführen, der wegen Fristüberschreitung fehlgeschlagen ist, ist selten sinnvoll. `retry_workflow()` setzt ihn auf `running` zurück und reiht den fehlgeschlagenen Schritt erneut ein, löscht oder verlängert aber nicht die Frist. Daher schlägt der Workflow bei der nächsten Fristenprüfung innerhalb von etwa einer Minute erneut fehl. Starte stattdessen einen neuen 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 );
}
```

## Fristen und Wartezeiten im Vergleich

Fristen gelten für die gesamte Workflow-Dauer. Wartezeiten (`->delay()`) pausieren den Workflow für eine festgelegte Dauer innerhalb der Schrittfolge. Ein Workflow mit einer Wartezeit von 1 Stunde und einer Frist von 2 Stunden schlägt fehl, wenn die Schritte ohne Wartezeit insgesamt mehr als 1 Stunde dauern.
