Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 65 additions & 4 deletions docs/features/events.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ sidebar_position: 12

Lifecycle events are dispatched at key stages of workflow and activity execution to notify your application of progress, completion, or failures. These are standard Laravel events — register listeners in your `EventServiceProvider` or with `Event::listen()`.

All V2 lifecycle events are dispatched **after the durable state is committed** to the database. This means listeners only observe events backed by committed truth — if a transaction rolls back, no event is dispatched.
`WorkflowCancelled` and `WorkflowTerminated` wait for the transaction on the run's storage connection to commit. Rejected commands and rolled-back storage writes emit neither event. Other engine transaction and lifecycle-ordering gaps remain tracked in [workflow#893](https://github.com/durable-workflow/workflow/issues/893). A transaction on a separate application database does not make workflow storage writes atomic.

## Event Identity

Expand All @@ -18,7 +18,7 @@ Every V2 event carries durable identity fields:
| `runId` | The specific execution run ID. |
| `workflowType` | The durable type key registered via `#[Type('...')]`. |
| `workflowClass` | The PHP class name of the workflow. |
| `committedAt` | ISO 8601 timestamp of when the durable record was committed (wall-clock commit time). |
| `committedAt` | ISO 8601 wall-clock timestamp captured when preparing the lifecycle notification. |

Activity events additionally include:

Expand Down Expand Up @@ -69,6 +69,8 @@ Event::listen(WorkflowCompleted::class, function (WorkflowCompleted $event) {

Dispatched when a workflow run fails terminally.

Run timeouts also dispatch `WorkflowFailed`. Expiry of a cooperative cancellation cleanup deadline dispatches `WorkflowCancelled` instead.

Additional fields:
- `exceptionClass`: The PHP exception class name.
- `message`: The exception message.
Expand All @@ -85,6 +87,49 @@ Event::listen(WorkflowFailed::class, function (WorkflowFailed $event) {
});
```

### WorkflowCancelled {#workflowcancelled}

Dispatched when immediate cancellation closes a run, or when cooperative cancellation closes it after cleanup completes or its deadline expires. A cancellation request alone does not dispatch this event.

In addition to the common identity fields:

| Field | Description |
|---|---|
| `reason` | The original cancellation command reason, or `null`. Cleanup completion and deadline messages do not replace it. |
| `closedAt` | The persisted run close time as a UTC ISO 8601 string. |

```php
use Workflow\V2\Events\WorkflowCancelled;

Event::listen(WorkflowCancelled::class, function (WorkflowCancelled $event) {
Log::info('Workflow cancelled', [
'instance_id' => $event->instanceId,
'run_id' => $event->runId,
'reason' => $event->reason,
'closed_at' => $event->closedAt,
]);
});
```

### WorkflowTerminated {#workflowterminated}

Dispatched when termination closes a run. It carries the same identity fields, `reason` and `closedAt`, using the termination command's reason. Termination does not execute workflow cleanup code.

```php
use Workflow\V2\Events\WorkflowTerminated;

Event::listen(WorkflowTerminated::class, function (WorkflowTerminated $event) {
Log::info('Workflow terminated', [
'instance_id' => $event->instanceId,
'run_id' => $event->runId,
'reason' => $event->reason,
'closed_at' => $event->closedAt,
]);
});
```

These are in-process Laravel notifications. A listener failure cannot undo a committed close. The events grant no authority to resume a closed run and do not guarantee durable delivery to an external system.

## Activity Events

### ActivityStarted
Expand Down Expand Up @@ -165,13 +210,13 @@ Event::listen(FailureRecorded::class, function (FailureRecorded $event) {

## Timestamp Semantics

The `committedAt` field on all events represents **commit time** — the wall-clock time at which the durable record (history event or failure record) was written to the database. This is distinct from:
The engine captures `committedAt` when preparing a lifecycle notification. It is a wall-clock timestamp, distinct from:

- **Workflow virtual time**: The logical time inside the workflow execution (used by timers).
- **Attempt time**: When a specific activity attempt started or finished.
- **Resume latency**: How long after a timer was due the workflow actually resumed.

Commit time is the most useful timestamp for external integrations because it reflects when the state became durable and observable.
For cancellation and termination, `closedAt` is the persisted run close timestamp in UTC. An enclosing storage transaction can commit later than when the event fields were captured. Record listener receipt time separately when measuring delivery latency.

## Lifecycle

Expand All @@ -195,6 +240,22 @@ Workflow\V2\Events\WorkflowFailed
Workflow\V2\Events\FailureRecorded (source: workflow_run)
```

A cancelled run ends with:

```
Workflow\V2\Events\WorkflowStarted
Workflow\V2\Events\WorkflowCancelled
```

Cooperative cleanup can emit activity events between these two notifications.

A terminated run ends with:

```
Workflow\V2\Events\WorkflowStarted
Workflow\V2\Events\WorkflowTerminated
```

## Event Namespace

V2 events live in the `Workflow\V2\Events` namespace. If you are upgrading an existing app, see [Migration](../migration.md) for the V1 compatibility event mapping.
76 changes: 65 additions & 11 deletions i18n/de/docusaurus-plugin-content-docs/current/features/events.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@ Aktivitätsausführung ausgelöst, um Ihre Anwendung über Fortschritt, Abschlus
oder Fehler zu informieren. Es sind normale Laravel-Ereignisse. Registrieren
Sie Listener im `EventServiceProvider` oder mit `Event::listen()`.

Alle V2-Lebenszyklusereignisse werden **nach dem Festschreiben des dauerhaften
Zustands** in der Datenbank ausgelöst. Listener sehen dadurch nur Ereignisse,
die durch festgeschriebene Fakten belegt sind. Wird eine Transaktion
zurückgerollt, wird kein Ereignis ausgelöst.
`WorkflowCancelled` und `WorkflowTerminated` warten auf den Commit der Transaktion auf der Speicherverbindung des Laufs. Abgelehnte Befehle und zurückgerollte Schreibvorgänge lösen keines dieser Ereignisse aus. Weitere Lücken bei Engine-Transaktionen und der Reihenfolge von Lebenszyklusereignissen werden in [workflow#893](https://github.com/durable-workflow/workflow/issues/893) verfolgt. Eine Transaktion auf einer separaten Anwendungsdatenbank macht Schreibvorgänge im Workflow-Speicher nicht atomar.

## Ereignisidentität {#event-identity}

Expand All @@ -24,7 +21,7 @@ Jedes V2-Ereignis enthält dauerhafte Identitätsfelder:
| `runId` | Die ID des konkreten Laufs. |
| `workflowType` | Der über `#[Type('...')]` registrierte dauerhafte Typschlüssel. |
| `workflowClass` | Der PHP-Klassenname des Workflows. |
| `committedAt` | ISO-8601-Zeitstempel des Festschreibens des dauerhaften Datensatzes, als reale Commit-Zeit. |
| `committedAt` | ISO-8601-Zeitstempel der realen Uhrzeit, erfasst beim Vorbereiten der Lebenszyklusbenachrichtigung. |

Aktivitätsereignisse enthalten zusätzlich:

Expand Down Expand Up @@ -77,6 +74,8 @@ Event::listen(WorkflowCompleted::class, function (WorkflowCompleted $event) {

Wird ausgelöst, wenn ein Workflow-Lauf endgültig fehlschlägt.

Bei Überschreitung des Zeitlimits eines Laufs wird ebenfalls `WorkflowFailed` ausgelöst. Läuft dagegen die Bereinigungsfrist einer kooperativen Stornierung ab, wird `WorkflowCancelled` ausgelöst.

Zusätzliche Felder:
- `exceptionClass`: Der PHP-Klassenname der Ausnahme.
- `message`: Die Ausnahmemeldung.
Expand All @@ -93,6 +92,49 @@ Event::listen(WorkflowFailed::class, function (WorkflowFailed $event) {
});
```

### WorkflowCancelled {#workflowcancelled}

Wird ausgelöst, wenn eine sofortige Stornierung einen Lauf schließt oder eine kooperative Stornierung ihn nach abgeschlossener Bereinigung beziehungsweise Ablauf der Bereinigungsfrist schließt. Die Stornierungsanfrage allein löst dieses Ereignis nicht aus.

Zusätzlich zu den gemeinsamen Identitätsfeldern:

| Feld | Beschreibung |
|---|---|
| `reason` | Der ursprüngliche Grund des Stornierungsbefehls oder `null`. Meldungen zum Abschluss oder Fristablauf der Bereinigung ersetzen ihn nicht. |
| `closedAt` | Der gespeicherte Abschlusszeitpunkt des Laufs als UTC-ISO-8601-Zeichenkette. |

```php
use Workflow\V2\Events\WorkflowCancelled;

Event::listen(WorkflowCancelled::class, function (WorkflowCancelled $event) {
Log::info('Workflow cancelled', [
'instance_id' => $event->instanceId,
'run_id' => $event->runId,
'reason' => $event->reason,
'closed_at' => $event->closedAt,
]);
});
```

### WorkflowTerminated {#workflowterminated}

Wird ausgelöst, wenn eine erzwungene Beendigung einen Lauf schließt. Es enthält dieselben Identitätsfelder sowie `reason` und `closedAt`, wobei der Grund aus dem Beendigungsbefehl stammt. Bei der erzwungenen Beendigung wird kein Bereinigungscode des Workflows ausgeführt.

```php
use Workflow\V2\Events\WorkflowTerminated;

Event::listen(WorkflowTerminated::class, function (WorkflowTerminated $event) {
Log::info('Workflow terminated', [
'instance_id' => $event->instanceId,
'run_id' => $event->runId,
'reason' => $event->reason,
'closed_at' => $event->closedAt,
]);
});
```

Dies sind prozessinterne Laravel-Benachrichtigungen. Ein Listener-Fehler kann einen festgeschriebenen Abschluss nicht rückgängig machen. Die Ereignisse berechtigen nicht zur Fortsetzung eines geschlossenen Laufs und garantieren keine dauerhafte Zustellung an ein externes System.

## Aktivitätsereignisse {#activity-events}

### ActivityStarted {#activitystarted}
Expand Down Expand Up @@ -179,17 +221,13 @@ Event::listen(FailureRecorded::class, function (FailureRecorded $event) {

## Zeitstempelsemantik {#timestamp-semantics}

Das Feld `committedAt` aller Ereignisse bezeichnet die **Commit-Zeit**:
die reale Uhrzeit, zu der der dauerhafte Datensatz (Historienereignis oder
Fehlerdatensatz) in die Datenbank geschrieben wurde. Dies unterscheidet sich
von:
Die Engine erfasst `committedAt` beim Vorbereiten einer Lebenszyklusbenachrichtigung. Dieser Zeitstempel der realen Uhrzeit unterscheidet sich von:

- **Virtueller Workflow-Zeit**: der logischen Zeit innerhalb der Workflow-Ausführung, die von Timern verwendet wird.
- **Versuchszeit**: dem Start- oder Abschlusszeitpunkt eines bestimmten Aktivitätsversuchs.
- **Fortsetzungslatenz**: der Zeit zwischen Fälligkeit eines Timers und tatsächlicher Fortsetzung des Workflows.

Für externe Integrationen ist die Commit-Zeit der nützlichste Zeitstempel,
weil sie angibt, wann der Zustand dauerhaft und beobachtbar wurde.
Bei Stornierung und erzwungener Beendigung ist `closedAt` der gespeicherte Abschlusszeitpunkt in UTC. Eine umschließende Speichertransaktion kann erst nach dem Erfassen der Ereignisfelder festgeschrieben werden. Erfassen Sie den Empfangszeitpunkt im Listener separat, wenn Sie die Zustelllatenz messen.

## Lebenszyklus {#lifecycle}

Expand All @@ -213,6 +251,22 @@ Workflow\V2\Events\WorkflowFailed
Workflow\V2\Events\FailureRecorded (source: workflow_run)
```

Ein stornierter Lauf endet mit:

```
Workflow\V2\Events\WorkflowStarted
Workflow\V2\Events\WorkflowCancelled
```

Bei kooperativer Bereinigung können zwischen diesen beiden Benachrichtigungen Aktivitätsereignisse auftreten.

Ein erzwungen beendeter Lauf endet mit:

```
Workflow\V2\Events\WorkflowStarted
Workflow\V2\Events\WorkflowTerminated
```

## Ereignis-Namespace {#event-namespace}

V2-Ereignisse liegen im Namespace `Workflow\V2\Events`. Bei einem Upgrade
Expand Down
2 changes: 1 addition & 1 deletion i18n/de/source-hashes.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"features/concurrency.md": "a7a3eb2274f7b14faf722494569b7663c07ab48afdf2e9225e58914b84cacbb4",
"features/condition-waits.md": "451261eda990c9591a0db69839d872184b5c64da6b537a582133095b8d4b599e",
"features/continue-as-new.md": "6b3cc8f8c5375726ff0b2544da01e7206e964908b436544e284068ab67aa3dbb",
"features/events.md": "fcb391862938b5e8cf44ad39f213fc3e55b2ecb7c6edebe6a83a1e58a60bf56e",
"features/events.md": "c466df05908748489226a3d1410c9203cf6f2986a4bb7539db1c5f82715abc7b",
"features/external-payload-storage.md": "acc312fa2f50a43c96e1d235439124d28a7048f0bf3abac34319467fcbf7e898",
"features/heartbeats.md": "e3d84178788dff92954e08d08f006def0a991a481f99301facbda8c6ca21a7a0",
"features/local-activities.md": "05fca8f2104d8f4e7bd8b48040f5615f18d0ee2795922fb65c56f8d3d70ed204",
Expand Down
69 changes: 65 additions & 4 deletions i18n/es/docusaurus-plugin-content-docs/current/features/events.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ sidebar_position: 12

Los eventos de ciclo de vida se despachan en etapas clave de workflows y actividades para notificar progreso, finalización o fallos a la aplicación. Son eventos estándar de Laravel: registra listeners en `EventServiceProvider` o con `Event::listen()`.

Todos los eventos de ciclo de vida V2 se despachan **después de confirmar el estado duradero** en la base de datos. Los listeners solo observan eventos respaldados por hechos confirmados: si se revierte una transacción, no se despacha ninguno.
`WorkflowCancelled` y `WorkflowTerminated` esperan a que se confirme la transacción en la conexión donde se almacena la ejecución. Los comandos rechazados y las escrituras revertidas no emiten ninguno de estos eventos. Las demás limitaciones de transacciones del motor y orden de eventos se siguen en [workflow#893](https://github.com/durable-workflow/workflow/issues/893). Una transacción en una base de datos independiente de la aplicación no hace atómicas las escrituras del almacenamiento del workflow.

## Identidad del evento {#event-identity}

Expand All @@ -18,7 +18,7 @@ Cada evento V2 contiene campos de identidad duradera:
| `runId` | ID de la ejecución concreta. |
| `workflowType` | Clave de tipo duradera registrada mediante `#[Type('...')]`. |
| `workflowClass` | Nombre de clase PHP del workflow. |
| `committedAt` | Fecha ISO 8601 de confirmación del registro duradero según el reloj real. |
| `committedAt` | Marca de tiempo ISO 8601 del reloj real, capturada al preparar la notificación del ciclo de vida. |

Los eventos de actividad también incluyen:

Expand Down Expand Up @@ -69,6 +69,8 @@ Event::listen(WorkflowCompleted::class, function (WorkflowCompleted $event) {

Se despacha cuando una ejecución falla de forma terminal.

Los tiempos de espera agotados de una ejecución también emiten `WorkflowFailed`. Si vence el plazo de limpieza de una cancelación cooperativa, se emite `WorkflowCancelled`.

Campos adicionales:
- `exceptionClass`: nombre de clase PHP de la excepción.
- `message`: mensaje de la excepción.
Expand All @@ -85,6 +87,49 @@ Event::listen(WorkflowFailed::class, function (WorkflowFailed $event) {
});
```

### WorkflowCancelled {#workflowcancelled}

Se despacha cuando una cancelación inmediata cierra una ejecución o cuando la cancelación cooperativa la cierra tras completar la limpieza o vencer su plazo. La solicitud de cancelación por sí sola no despacha este evento.

Además de los campos de identidad comunes:

| Campo | Descripción |
|---|---|
| `reason` | Motivo original del comando de cancelación, o `null`. Los mensajes de fin de limpieza o vencimiento del plazo no lo sustituyen. |
| `closedAt` | Hora de cierre persistida de la ejecución como cadena ISO 8601 en UTC. |

```php
use Workflow\V2\Events\WorkflowCancelled;

Event::listen(WorkflowCancelled::class, function (WorkflowCancelled $event) {
Log::info('Workflow cancelled', [
'instance_id' => $event->instanceId,
'run_id' => $event->runId,
'reason' => $event->reason,
'closed_at' => $event->closedAt,
]);
});
```

### WorkflowTerminated {#workflowterminated}

Se despacha cuando una terminación cierra la ejecución. Incluye los mismos campos de identidad, `reason` y `closedAt`, con el motivo del comando de terminación. La terminación no ejecuta el código de limpieza del workflow.

```php
use Workflow\V2\Events\WorkflowTerminated;

Event::listen(WorkflowTerminated::class, function (WorkflowTerminated $event) {
Log::info('Workflow terminated', [
'instance_id' => $event->instanceId,
'run_id' => $event->runId,
'reason' => $event->reason,
'closed_at' => $event->closedAt,
]);
});
```

Son notificaciones Laravel dentro del proceso. Un fallo del listener no puede deshacer un cierre confirmado. Estos eventos no autorizan a reanudar una ejecución cerrada ni garantizan la entrega duradera a un sistema externo.

## Eventos de actividad {#activity-events}

### ActivityStarted {#activitystarted}
Expand Down Expand Up @@ -165,13 +210,13 @@ Event::listen(FailureRecorded::class, function (FailureRecorded $event) {

## Semántica de las marcas de tiempo {#timestamp-semantics}

`committedAt` representa la **hora de confirmación**: el instante del reloj real en que se escribió en la base de datos el registro duradero (evento de historial o fallo). Es distinto de:
El motor captura `committedAt` al preparar una notificación del ciclo de vida. Es una marca de tiempo del reloj real, distinta de:

- **Tiempo virtual del workflow**: tiempo lógico interno, usado por los temporizadores.
- **Tiempo del intento**: cuándo empezó o terminó un intento concreto de actividad.
- **Latencia de reanudación**: cuánto tardó en reanudarse el workflow después de vencer un temporizador.

La hora de confirmación es la más útil para integraciones externas porque refleja cuándo el estado se volvió duradero y observable.
En cancelaciones y terminaciones, `closedAt` es la hora de cierre persistida en UTC. Una transacción externa de almacenamiento puede confirmarse después de capturar los campos del evento. Registra por separado la hora de recepción del listener para medir la latencia de entrega.

## Ciclo de vida {#lifecycle}

Expand All @@ -195,6 +240,22 @@ Workflow\V2\Events\WorkflowFailed
Workflow\V2\Events\FailureRecorded (source: workflow_run)
```

Una ejecución cancelada termina con:

```
Workflow\V2\Events\WorkflowStarted
Workflow\V2\Events\WorkflowCancelled
```

La limpieza cooperativa puede emitir eventos de actividad entre estas dos notificaciones.

Una ejecución terminada finaliza con:

```
Workflow\V2\Events\WorkflowStarted
Workflow\V2\Events\WorkflowTerminated
```

## Espacio de nombres de eventos {#event-namespace}

Los eventos V2 están en `Workflow\V2\Events`. Si actualizas una aplicación existente, consulta la correspondencia de eventos compatibles V1 en [Migración](../migration.md).
2 changes: 1 addition & 1 deletion i18n/es/source-hashes.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"features/concurrency.md": "a7a3eb2274f7b14faf722494569b7663c07ab48afdf2e9225e58914b84cacbb4",
"features/condition-waits.md": "451261eda990c9591a0db69839d872184b5c64da6b537a582133095b8d4b599e",
"features/continue-as-new.md": "6b3cc8f8c5375726ff0b2544da01e7206e964908b436544e284068ab67aa3dbb",
"features/events.md": "fcb391862938b5e8cf44ad39f213fc3e55b2ecb7c6edebe6a83a1e58a60bf56e",
"features/events.md": "c466df05908748489226a3d1410c9203cf6f2986a4bb7539db1c5f82715abc7b",
"features/external-payload-storage.md": "acc312fa2f50a43c96e1d235439124d28a7048f0bf3abac34319467fcbf7e898",
"features/heartbeats.md": "e3d84178788dff92954e08d08f006def0a991a481f99301facbda8c6ca21a7a0",
"features/local-activities.md": "05fca8f2104d8f4e7bd8b48040f5615f18d0ee2795922fb65c56f8d3d70ed204",
Expand Down
Loading
Loading