
# Workflows

Workflows unterteilen lang laufende Aufgaben in einzelne Schritte. Jeder Schritt speichert seine Ausgabe in einem gemeinsamen Statusobjekt in der Datenbank. Wenn PHP mitten in einem Schritt ausfällt, wiederholt der Worker diesen Schritt und behält den gesamten vorherigen Status bei.

## Was sind Workflows?

Ein Workflow ist eine geordnete Abfolge von Schritten. Jeder Schritt ist eine PHP-Klasse, die den gesammelten Status aller vorherigen Schritte erhält und neue Daten zurückgibt, die mit dem Status zusammengeführt werden. Der Workflow schreitet Schritt für Schritt voran; jeder Übergang ist in eine atomare MySQL-Transaktion eingebettet.

```php
use Queuety\Queuety;

$workflow_id = Queuety::workflow( 'generate_report' )
    ->then( FetchDataHandler::class )
    ->then( CallLLMHandler::class )
    ->then( FormatOutputHandler::class )
    ->dispatch( [ 'user_id' => 42 ] );
```

## Status sammeln

Die anfänglichen Nutzdaten, die du an `dispatch()` übergibst, bilden den Ausgangsstatus. Die zurückgegebenen Schlüssel jedes Schritts werden mit dem Status zusammengeführt. Schlüssel, die mit `_` beginnen, sind für Steuerwerte wie `_next_step` reserviert und werden nicht mit dem öffentlichen Status zusammengeführt:

```
dispatch(['user_id' => 42])

Step 0: FetchDataHandler   -> returns ['user_name' => 'Alice']
  state: {user_id: 42, user_name: 'Alice'}

Step 1: CallLLMHandler     -> returns ['llm_response' => '...']
  state: {user_id: 42, user_name: 'Alice', llm_response: '...'}

Step 2: FormatOutputHandler -> returns ['report_url' => '/reports/42.pdf']
  state: {user_id: 42, user_name: 'Alice', llm_response: '...', report_url: '/reports/42.pdf'}
```

Jeder Schritt erhält den vollständig gesammelten Status. So kannst du Daten einfach zwischen Schritten weitergeben, ohne externen Speicher zu benötigen.

## Fortsetzen

Workflows sind dauerhaft, weil ihr Status nach jedem Schritt in der Datenbank gespeichert wird. Stürzt der Worker während Schritt 1 ab, startet der Workflow wieder bei Schritt 1, während die Ausgabe von Schritt 0 bereits im Status enthalten ist.

Die Schrittgrenze ist eine einzelne MySQL-Transaktion, die atomar Folgendes ausführt:
1. Aktualisiert den Workflow-Status mit der Ausgabe des Schritts
2. Markiert den Auftrag des aktuellen Schritts als abgeschlossen
3. Reiht den Auftrag des nächsten Schritts ein

So geht garantiert kein Status verloren, auch nicht bei Abstürzen, Zeitüberschreitungen oder schwerwiegenden PHP-Fehlern.

## Workflow-Lebenszyklus

```
dispatch() -> running -> step 0 -> step 1 -> ... -> step N -> completed
                  |                   |
                  |                   +-> failed -> retry -> running (from failed step)
                  |
                  +-> paused -> resumed -> running
                  |
                  +-> waiting_for_signal -> signal received -> running
                  |
                  +-> waiting_for_workflows -> dependency settles -> running
                  |
                  +-> cancelled (via cancel_workflow)
```

| Status | Beschreibung |
|---|---|
| `running` | Schritte werden aktiv verarbeitet |
| `completed` | Alle Schritte wurden erfolgreich abgeschlossen |
| `failed` | Ein Schritt ist nach Ausschöpfen aller Wiederholungen fehlgeschlagen |
| `paused` | Manuell pausiert. Laufende Arbeit kann noch abgeschlossen werden, aber weitere Schritte werden bis zur Fortsetzung nicht eingereiht |
| `waiting_for_signal` | Wartet über `Queuety::signal()` auf ein externes Signal |
| `waiting_for_workflows` | Wartet über `wait_for_workflow()` oder `wait_for_workflows()` auf den Abschluss eines oder mehrerer anderer Workflows |
| `cancelled` | Über `Queuety::cancel_workflow()` ausdrücklich abgebrochen. Ausstehende Aufträge werden zurückgestellt und optional wird ein Bereinigungs-Handler ausgeführt. |

## Workflows verwalten

Status prüfen:

```php
$state = Queuety::workflow_status( $workflow_id );
echo $state->status->value;   // 'running'
echo $state->current_step;    // 1
echo $state->total_steps;     // 3
print_r( $state->waiting_for ); // ['42'] while waiting on another workflow
print_r( $state->wait_details ); // matched/remaining blockers, result key, correlation info
```

Pausieren und fortsetzen:

```php
Queuety::pause_workflow( $workflow_id );
Queuety::resume_workflow( $workflow_id );
```

Einen fehlgeschlagenen Workflow ab dem fehlgeschlagenen Schritt erneut ausführen:

```php
Queuety::retry_workflow( $workflow_id );
```

Einen Workflow abbrechen und Bereinigungs-Handler ausführen:

```php
Queuety::cancel_workflow( $workflow_id );
```

Weitere Informationen zu Bereinigungs-Handlern und den Folgen eines Workflow-Abbruchs findest du unter [Abbruch](https://queuety.inline0.dev/de/docs/workflows/cancellation).

## Workflow-Optionen

Lege Warteschlange, Priorität und Wiederholungsverhalten für alle Schritte eines Workflows fest:

```php
use Queuety\Enums\Priority;

Queuety::workflow( 'important_pipeline' )
    ->on_queue( 'pipelines' )
    ->with_priority( Priority::High )
    ->max_attempts( 5 )
    ->on_cancel( PipelineCleanupHandler::class )
    ->prune_state_after( 3 )
    ->then( StepA::class )
    ->then( StepB::class )
    ->dispatch( $payload );
```

Die Methode `on_cancel()` registriert einen Bereinigungs-Handler, der beim Abbruch des Workflows ausgeführt wird. Siehe [Abbruch](https://queuety.inline0.dev/de/docs/workflows/cancellation).

Die Methode `prune_state_after()` aktiviert das automatische Entfernen alter Schrittausgaben, damit der Workflow-Status begrenzt bleibt. Siehe [Statusbereinigung](https://queuety.inline0.dev/de/docs/features/state-pruning).

Verwende `compensate_with()`, um einen Kompensations-Handler pro Schritt zuzuweisen. Verwende `compensate_on_failure()`, wenn abgeschlossene Schrittkompensationen nach einem Workflow-Fehler automatisch ausgeführt werden sollen, nicht nur bei einem ausdrücklichen Abbruch. Siehe [Kompensation](https://queuety.inline0.dev/de/docs/workflows/compensation).

Verwende Workflow-Schutzmaßnahmen, wenn du eine sicherere Orchestrierung lang laufender Prozesse benötigst: `version()` versieht eine Definition mit einer Versionsbezeichnung auf Anwendungsebene, Queuety speichert für jede Ausführung zusätzlich einen deterministischen Definitions-Hash, `idempotency_key()` macht den Start bei Wiederholungen oder doppelten Anfragen dauerhaft zuverlässig und `max_transitions()`, `max_for_each_items()` und `max_state_bytes()` lassen außer Kontrolle geratene Ausführungen fehlschlagen, bevor sie eskalieren. Siehe [Schutzmaßnahmen](https://queuety.inline0.dev/de/docs/workflows/guardrails).

## Schritttypen

Queuety unterstützt elf Schritttypen innerhalb eines Workflows:

- [Sequenzielle Ketten](https://queuety.inline0.dev/de/docs/workflows/chains) mit `->then()` für die Ausführung nacheinander
- [Parallele Gruppen](https://queuety.inline0.dev/de/docs/workflows/parallel) mit `->parallel()` für die gleichzeitige Ausführung
- [Dynamische For-each-Schritte](https://queuety.inline0.dev/de/docs/workflows/for-each) mit `->for_each()` für zur Laufzeit ermittelte Zweige und festgelegte Abschlussbedingungen
- [Asynchrone Übergaben](https://queuety.inline0.dev/de/docs/workflows/async-handoffs) mit `->start_workflows()` oder `->start_agents()`, um unabhängige untergeordnete Workflows aus zur Laufzeit ermittelten Elementen zu starten
- [Bedingte Verzweigungen](https://queuety.inline0.dev/de/docs/workflows/conditional) mit benannten Schritten und `_next_step`
- [Wiederholungen](https://queuety.inline0.dev/de/docs/workflows/repeats) mit `->repeat_until()` und `->repeat_while()` für dauerhafte Rücksprünge zu früheren benannten Schritten
- [Workflows ausführen](https://queuety.inline0.dev/de/docs/workflows/run-workflows) mit `->run_workflow()` für verschachtelte Komposition
- [Dauerhafte Verzögerungen](https://queuety.inline0.dev/de/docs/workflows/delays) mit `->delay()` für zeitbasierte Verzögerungen
- [Signale](https://queuety.inline0.dev/de/docs/workflows/signals) mit `->wait_for_signal()`, `->wait_for_signals()`, `->wait_for_approval()`, `->wait_for_input()` und `->wait_for_decision()` für externe Ereignisauslöser
- [Workflow-Abhängigkeiten](https://queuety.inline0.dev/de/docs/workflows/dependencies) mit `->wait_for_workflow()`, `->wait_for_workflows()` und `->wait_for_agents()` zur Koordination zwischen Workflows
- [Streaming-Schritte](https://queuety.inline0.dev/de/docs/workflows/streaming) mit der Schnittstelle `StreamingStep` für dauerhafte, in Blöcken ausgegebene Daten

## Häufige Anwendungsfälle

Wenn du autonome oder teilautonome Systeme entwickelst, beginne mit [Agenten-Orchestrierung](https://queuety.inline0.dev/de/docs/workflows/agent-orchestration). Dort wird gezeigt, wie `for_each()`, `start_agents()`, `wait_for_agents()`, `wait_for_workflow()` und `wait_for_decision()` in echten Planer-Ausführer- und Human-Review-Abläufen zusammenwirken.
