diff --git a/docs/features/events.md b/docs/features/events.md index 5a89f94ef66..1b8ce49852d 100644 --- a/docs/features/events.md +++ b/docs/features/events.md @@ -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 @@ -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: @@ -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. @@ -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 @@ -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 @@ -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. diff --git a/i18n/de/docusaurus-plugin-content-docs/current/features/events.md b/i18n/de/docusaurus-plugin-content-docs/current/features/events.md index 6f7110930bb..874d9db978e 100644 --- a/i18n/de/docusaurus-plugin-content-docs/current/features/events.md +++ b/i18n/de/docusaurus-plugin-content-docs/current/features/events.md @@ -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} @@ -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: @@ -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. @@ -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} @@ -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} @@ -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 diff --git a/i18n/de/source-hashes.json b/i18n/de/source-hashes.json index ba519e457c8..66bd757583f 100644 --- a/i18n/de/source-hashes.json +++ b/i18n/de/source-hashes.json @@ -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", diff --git a/i18n/es/docusaurus-plugin-content-docs/current/features/events.md b/i18n/es/docusaurus-plugin-content-docs/current/features/events.md index bb4c8ea707c..6d15dda0b11 100644 --- a/i18n/es/docusaurus-plugin-content-docs/current/features/events.md +++ b/i18n/es/docusaurus-plugin-content-docs/current/features/events.md @@ -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} @@ -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: @@ -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. @@ -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} @@ -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} @@ -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). diff --git a/i18n/es/source-hashes.json b/i18n/es/source-hashes.json index ba519e457c8..66bd757583f 100644 --- a/i18n/es/source-hashes.json +++ b/i18n/es/source-hashes.json @@ -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", diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/features/events.md b/i18n/fr/docusaurus-plugin-content-docs/current/features/events.md index dd34316a1ee..9f5b9910c7c 100644 --- a/i18n/fr/docusaurus-plugin-content-docs/current/features/events.md +++ b/i18n/fr/docusaurus-plugin-content-docs/current/features/events.md @@ -6,7 +6,7 @@ sidebar_position: 12 Les événements de cycle de vie sont émis aux étapes clés des workflows et activités pour informer votre application de la progression, de l’achèvement ou des échecs. Ce sont des événements Laravel standards. Enregistrez des écouteurs dans votre `EventServiceProvider` ou avec `Event::listen()`. -Tous les événements de cycle de vie v2 sont émis **après validation de l’état durable** en base. Les écouteurs n’observent donc que des événements fondés sur des faits validés. Si une transaction est annulée, aucun événement n’est émis. +`WorkflowCancelled` et `WorkflowTerminated` attendent la validation de la transaction sur la connexion de stockage de l’exécution. Les commandes refusées et les écritures annulées n’émettent aucun de ces deux événements. Les autres limites des transactions du moteur et de l’ordre des événements sont suivies dans [workflow#893](https://github.com/durable-workflow/workflow/issues/893). Une transaction sur une base distincte de l’application ne rend pas atomiques les écritures dans le stockage du workflow. ## Identité des événements {#event-identity} @@ -18,7 +18,7 @@ Chaque événement v2 porte des champs d’identité durable : | `runId` | Identifiant de l’exécution précise. | | `workflowType` | Clé de type durable enregistrée via `#[Type('...')]`. | | `workflowClass` | Nom de la classe PHP du workflow. | -| `committedAt` | Horodatage ISO 8601 de validation de l’enregistrement durable, selon l’horloge réelle. | +| `committedAt` | Horodatage ISO 8601 de l’horloge réelle, relevé lors de la préparation de la notification de cycle de vie. | Les événements d’activité incluent aussi : @@ -69,6 +69,8 @@ Event::listen(WorkflowCompleted::class, function (WorkflowCompleted $event) { Émis lorsqu’une exécution de workflow échoue de façon terminale. +L’expiration du délai d’exécution émet également `WorkflowFailed`. L’expiration du délai de nettoyage d’une annulation coopérative émet en revanche `WorkflowCancelled`. + Champs supplémentaires : - `exceptionClass` : nom de la classe d’exception PHP. - `message` : message de l’exception. @@ -85,6 +87,49 @@ Event::listen(WorkflowFailed::class, function (WorkflowFailed $event) { }); ``` +### WorkflowCancelled {#workflowcancelled} + +Émis lorsqu’une annulation immédiate clôt l’exécution, ou lorsqu’une annulation coopérative la clôt après la fin du nettoyage ou l’expiration de son délai. La seule demande d’annulation n’émet pas cet événement. + +En plus des champs d’identité communs : + +| Champ | Description | +|---|---| +| `reason` | Motif d’origine de la commande d’annulation, ou `null`. Les messages de fin de nettoyage ou d’expiration du délai ne le remplacent pas. | +| `closedAt` | Heure de clôture persistée de l’exécution, sous forme de chaîne 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} + +Émis lorsqu’une terminaison forcée clôt l’exécution. Il contient les mêmes champs d’identité, `reason` et `closedAt`, avec le motif de la commande de terminaison. La terminaison forcée n’exécute pas le code de nettoyage du 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, + ]); +}); +``` + +Ce sont des notifications Laravel internes au processus. Un échec d’écouteur ne peut pas annuler une clôture validée. Les événements ne donnent aucune autorisation de reprendre une exécution close et ne garantissent pas une livraison durable à un système externe. + ## Événements d’activité {#activity-events} ### ActivityStarted {#activitystarted} @@ -165,13 +210,13 @@ Event::listen(FailureRecorded::class, function (FailureRecorded $event) { ## Sémantique des horodatages {#timestamp-semantics} -Le champ `committedAt` de chaque événement représente **l’heure de validation**, soit l’heure réelle à laquelle l’enregistrement durable (événement d’historique ou échec) a été écrit en base. Elle est distincte de : +Le moteur relève `committedAt` lors de la préparation d’une notification de cycle de vie. Cet horodatage de l’horloge réelle est distinct de : - **L’heure virtuelle du workflow** : temps logique de son exécution, utilisé par les temporisateurs. - **L’heure de tentative** : début ou fin d’une tentative d’activité précise. - **La latence de reprise** : délai entre l’échéance d’un temporisateur et la reprise réelle du workflow. -L’heure de validation est la plus utile aux intégrations externes, car elle indique quand l’état est devenu durable et observable. +Pour une annulation ou une terminaison forcée, `closedAt` est l’horodatage de clôture persisté en UTC. Une transaction de stockage englobante peut être validée après le relevé des champs de l’événement. Pour mesurer la latence de livraison, consignez séparément l’heure de réception par l’écouteur. ## Cycle de vie {#lifecycle} @@ -195,6 +240,22 @@ Workflow\V2\Events\WorkflowFailed Workflow\V2\Events\FailureRecorded (source: workflow_run) ``` +Une exécution annulée se termine par : + +``` +Workflow\V2\Events\WorkflowStarted +Workflow\V2\Events\WorkflowCancelled +``` + +Le nettoyage coopératif peut émettre des événements d’activité entre ces deux notifications. + +Une exécution terminée de force se termine par : + +``` +Workflow\V2\Events\WorkflowStarted +Workflow\V2\Events\WorkflowTerminated +``` + ## Espace de noms des événements {#event-namespace} Les événements v2 résident dans l’espace de noms `Workflow\V2\Events`. Pour mettre à niveau une application existante, consultez [Migration](../migration.md) pour la correspondance des événements de compatibilité v1. diff --git a/i18n/fr/source-hashes.json b/i18n/fr/source-hashes.json index ba519e457c8..66bd757583f 100644 --- a/i18n/fr/source-hashes.json +++ b/i18n/fr/source-hashes.json @@ -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", diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/features/events.md b/i18n/ja/docusaurus-plugin-content-docs/current/features/events.md index 88cffc038b5..3ff8d5a8229 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/features/events.md +++ b/i18n/ja/docusaurus-plugin-content-docs/current/features/events.md @@ -6,7 +6,7 @@ sidebar_position: 12 ライフサイクルイベントは実行の重要な段階で発行され、進捗、完了、失敗をアプリに通知します。標準の Laravel イベントなので、`EventServiceProvider` または `Event::listen()` にリスナーを登録します。 -v2 の全イベントは、**永続状態をデータベースにコミットした後**に発行します。リスナーが見るのはコミット済み事実に裏付けられたイベントだけです。トランザクションがロールバックすれば発行しません。 +`WorkflowCancelled` と `WorkflowTerminated` は、実行の保存先接続上のトランザクションがコミットされるまで待ちます。拒否されたコマンドやロールバックされた書き込みからは、どちらのイベントも発行されません。エンジンのトランザクションやライフサイクルイベントの順序に関するその他の問題は [workflow#893](https://github.com/durable-workflow/workflow/issues/893) で追跡しています。別のアプリケーション用データベース上のトランザクションは、ワークフローの保存先への書き込みをアトミックにはしません。 ## イベントの識別情報 {#event-identity} @@ -18,7 +18,7 @@ v2 の全イベントは、**永続状態をデータベースにコミットし | `runId` | 特定の実行 ID。 | | `workflowType` | `#[Type('...')]` で登録した永続型キー。 | | `workflowClass` | ワークフローの PHP クラス名。 | -| `committedAt` | 永続記録のコミット時刻の ISO 8601 タイムスタンプ(実時計)。 | +| `committedAt` | ライフサイクル通知の準備時に記録した、実時計による ISO 8601 タイムスタンプ。 | アクティビティイベントはさらに次を含みます。 @@ -69,6 +69,8 @@ Event::listen(WorkflowCompleted::class, function (WorkflowCompleted $event) { 実行が終端の失敗に至ったときに発行します。 +実行のタイムアウトでも `WorkflowFailed` を発行します。一方、協調キャンセルのクリーンアップ期限が切れた場合は `WorkflowCancelled` を発行します。 + 追加フィールド: - `exceptionClass`: PHP 例外クラス名。 - `message`: 例外メッセージ。 @@ -85,6 +87,49 @@ Event::listen(WorkflowFailed::class, function (WorkflowFailed $event) { }); ``` +### WorkflowCancelled {#workflowcancelled} + +即時キャンセルで実行を閉じたとき、または協調キャンセルでクリーンアップが完了するか期限が切れて実行を閉じたときに発行します。キャンセル要求だけではこのイベントを発行しません。 + +共通の識別フィールドに加えて、次を含みます。 + +| フィールド | 説明 | +|---|---| +| `reason` | キャンセルコマンドの元の理由、または `null`。クリーンアップ完了や期限切れのメッセージで置き換えません。 | +| `closedAt` | 永続化した実行の終了時刻を表す UTC の ISO 8601 文字列。 | + +```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} + +強制終了で実行を閉じたときに発行します。同じ識別フィールドと `reason`、`closedAt` を持ち、理由には強制終了コマンドの値を使います。強制終了ではワークフローのクリーンアップコードを実行しません。 + +```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, + ]); +}); +``` + +これらはプロセス内の Laravel 通知です。リスナーの失敗によって、コミット済みの終了を取り消すことはできません。イベントは閉じた実行を再開する権限を与えず、外部システムへの永続的な配信も保証しません。 + ## アクティビティイベント {#activity-events} ### ActivityStarted {#activitystarted} @@ -165,13 +210,13 @@ Event::listen(FailureRecorded::class, function (FailureRecorded $event) { ## タイムスタンプの意味 {#timestamp-semantics} -全イベントの `committedAt` は**コミット時刻**、つまり永続記録(履歴イベントや失敗記録)をデータベースに書き込んだ実時計の時刻です。次とは異なります。 +エンジンはライフサイクル通知の準備時に `committedAt` を記録します。これは実時計のタイムスタンプで、次とは異なります。 - **ワークフローの仮想時刻**: 実行内の論理時刻(タイマーで使用)。 - **試行時刻**: 特定の試行の開始・終了時刻。 - **再開レイテンシ**: タイマー期限から実際の再開までの時間。 -コミット時刻は状態が永続化され観測可能になった時点を示すため、外部統合で最も役立つ時刻です。 +キャンセルと強制終了では、`closedAt` は永続化した実行の終了時刻を UTC で表します。外側のストレージトランザクションは、イベントの各フィールドを記録した後にコミットされる場合があります。配信レイテンシを測る際は、リスナーの受信時刻を別途記録してください。 ## ライフサイクル {#lifecycle} @@ -195,6 +240,22 @@ Workflow\V2\Events\WorkflowFailed Workflow\V2\Events\FailureRecorded (source: workflow_run) ``` +キャンセルされた実行は次のイベントで終わります。 + +``` +Workflow\V2\Events\WorkflowStarted +Workflow\V2\Events\WorkflowCancelled +``` + +協調クリーンアップでは、この二つの通知の間にアクティビティイベントを発行する場合があります。 + +強制終了された実行は次のイベントで終わります。 + +``` +Workflow\V2\Events\WorkflowStarted +Workflow\V2\Events\WorkflowTerminated +``` + ## イベントの名前空間 {#event-namespace} v2 イベントは `Workflow\V2\Events` 名前空間にあります。既存アプリのアップグレードでは、v1 互換イベントの対応を[移行](../migration.md)で確認してください。 diff --git a/i18n/ja/source-hashes.json b/i18n/ja/source-hashes.json index ba519e457c8..66bd757583f 100644 --- a/i18n/ja/source-hashes.json +++ b/i18n/ja/source-hashes.json @@ -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", diff --git a/i18n/pt-BR/docusaurus-plugin-content-docs/current/features/events.md b/i18n/pt-BR/docusaurus-plugin-content-docs/current/features/events.md index ed825d87233..7d3d4f78ee9 100644 --- a/i18n/pt-BR/docusaurus-plugin-content-docs/current/features/events.md +++ b/i18n/pt-BR/docusaurus-plugin-content-docs/current/features/events.md @@ -6,7 +6,7 @@ sidebar_position: 12 Eventos de ciclo de vida são disparados em etapas importantes da execução de workflows e atividades para informar à aplicação sobre progresso, conclusão ou falhas. São eventos padrão do Laravel. Registre listeners no seu `EventServiceProvider` ou com `Event::listen()`. -Todos os eventos de ciclo de vida V2 são disparados **depois que o estado durável é confirmado** no banco. Assim, listeners só observam eventos respaldados por dados confirmados. Se uma transação for revertida, nenhum evento é disparado. +`WorkflowCancelled` e `WorkflowTerminated` aguardam a confirmação da transação na conexão que armazena a execução. Comandos rejeitados e gravações revertidas não emitem nenhum desses eventos. Outras limitações das transações do mecanismo e da ordem dos eventos de ciclo de vida são acompanhadas em [workflow#893](https://github.com/durable-workflow/workflow/issues/893). Uma transação em um banco separado da aplicação não torna atômicas as gravações no armazenamento do workflow. ## Identidade dos eventos {#event-identity} @@ -18,7 +18,7 @@ Todo evento V2 contém campos de identidade durável: | `runId` | O ID da execução específica. | | `workflowType` | A chave de tipo durável registrada via `#[Type('...')]`. | | `workflowClass` | O nome da classe PHP do workflow. | -| `committedAt` | Horário ISO 8601 em que o registro durável foi confirmado (hora real da confirmação). | +| `committedAt` | Marca de tempo ISO 8601 do relógio real, capturada ao preparar a notificação de ciclo de vida. | Eventos de atividade também incluem: @@ -69,6 +69,8 @@ Event::listen(WorkflowCompleted::class, function (WorkflowCompleted $event) { Disparado quando uma execução de workflow falha de forma terminal. +O estouro do tempo limite de uma execução também dispara `WorkflowFailed`. Já o vencimento do prazo de limpeza de uma solicitação de cancelamento cooperativo dispara `WorkflowCancelled`. + Campos adicionais: - `exceptionClass`: O nome da classe PHP da exceção. - `message`: A mensagem da exceção. @@ -85,6 +87,49 @@ Event::listen(WorkflowFailed::class, function (WorkflowFailed $event) { }); ``` +### WorkflowCancelled {#workflowcancelled} + +Disparado quando o cancelamento imediato fecha uma execução ou quando o cancelamento cooperativo a fecha após concluir a limpeza ou vencer seu prazo. A solicitação de cancelamento por si só não dispara esse evento. + +Além dos campos de identidade comuns: + +| Campo | Descrição | +|---|---| +| `reason` | Motivo original do comando de cancelamento, ou `null`. Mensagens de conclusão da limpeza ou de vencimento do prazo não o substituem. | +| `closedAt` | Horário persistido de fechamento da execução como string ISO 8601 em 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} + +Disparado quando o encerramento forçado fecha uma execução. Contém os mesmos campos de identidade, `reason` e `closedAt`, com o motivo do comando de encerramento. O encerramento forçado não executa o código de limpeza do 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, + ]); +}); +``` + +Estas são notificações Laravel dentro do processo. Uma falha no listener não pode desfazer um fechamento confirmado. Os eventos não autorizam a retomada de uma execução fechada nem garantem entrega durável a um sistema externo. + ## Eventos de atividade {#activity-events} ### ActivityStarted {#activitystarted} @@ -165,13 +210,13 @@ Event::listen(FailureRecorded::class, function (FailureRecorded $event) { ## Semântica dos horários {#timestamp-semantics} -O campo `committedAt` em todos os eventos representa o **horário da confirmação**: a hora real em que o registro durável, seja evento de histórico ou registro de falha, foi gravado no banco. Ele é diferente de: +O mecanismo captura `committedAt` ao preparar uma notificação de ciclo de vida. É uma marca de tempo do relógio real, diferente de: - **Tempo virtual do workflow**: O tempo lógico dentro da execução do workflow, usado por temporizadores. - **Horário da tentativa**: Quando uma tentativa específica de atividade iniciou ou terminou. - **Latência de retomada**: Quanto tempo depois do vencimento de um temporizador o workflow efetivamente retomou. -O horário da confirmação é o mais útil para integrações externas, pois reflete quando o estado se tornou durável e observável. +Para cancelamento e encerramento forçado, `closedAt` é o horário persistido de fechamento em UTC. Uma transação externa de armazenamento pode ser confirmada depois da captura dos campos do evento. Registre separadamente o horário de recebimento no listener ao medir a latência de entrega. ## Ciclo de vida {#lifecycle} @@ -195,6 +240,22 @@ Workflow\V2\Events\WorkflowFailed Workflow\V2\Events\FailureRecorded (source: workflow_run) ``` +Uma execução cancelada termina com: + +``` +Workflow\V2\Events\WorkflowStarted +Workflow\V2\Events\WorkflowCancelled +``` + +A limpeza cooperativa pode emitir eventos de atividade entre essas duas notificações. + +Uma execução encerrada à força termina com: + +``` +Workflow\V2\Events\WorkflowStarted +Workflow\V2\Events\WorkflowTerminated +``` + ## Namespace dos eventos {#event-namespace} Os eventos V2 ficam no namespace `Workflow\V2\Events`. Se estiver atualizando uma aplicação existente, consulte [Migração](../migration.md) para conhecer o mapeamento dos eventos de compatibilidade V1. diff --git a/i18n/pt-BR/source-hashes.json b/i18n/pt-BR/source-hashes.json index ba519e457c8..66bd757583f 100644 --- a/i18n/pt-BR/source-hashes.json +++ b/i18n/pt-BR/source-hashes.json @@ -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", diff --git a/i18n/uk/docusaurus-plugin-content-docs/current/features/events.md b/i18n/uk/docusaurus-plugin-content-docs/current/features/events.md index ceb2ee0ed64..2423399abc8 100644 --- a/i18n/uk/docusaurus-plugin-content-docs/current/features/events.md +++ b/i18n/uk/docusaurus-plugin-content-docs/current/features/events.md @@ -6,7 +6,7 @@ sidebar_position: 12 Події життєвого циклу надсилаються на ключових етапах виконання workflow й activity, щоб повідомляти застосунок про поступ, завершення чи збої. Це стандартні події Laravel. Реєструйте слухачі в `EventServiceProvider` або через `Event::listen()`. -Усі події життєвого циклу V2 надсилаються **після фіксації стійкого стану** в базі даних. Слухачі бачать лише події, підтверджені зафіксованими фактами. Якщо транзакція відкочується, подія не надсилається. +`WorkflowCancelled` і `WorkflowTerminated` очікують фіксації транзакції на з’єднанні, у якому зберігається запуск. Відхилені команди та відкочені записи до сховища не спричиняють жодної з цих подій. Інші прогалини транзакцій рушія та порядку подій життєвого циклу відстежуються у [workflow#893](https://github.com/durable-workflow/workflow/issues/893). Транзакція в окремій базі даних застосунку не робить записи до сховища workflow атомарними. ## Ідентичність подій {#event-identity} @@ -18,7 +18,7 @@ sidebar_position: 12 | `runId` | ID конкретного запуску виконання. | | `workflowType` | Стійкий ключ типу, зареєстрований через `#[Type('...')]`. | | `workflowClass` | Назва PHP-класу workflow. | -| `committedAt` | Часова позначка ISO 8601 фіксації стійкого запису: реальний час фіксації. | +| `committedAt` | Часова позначка реального годинника у форматі ISO 8601, зафіксована під час підготовки сповіщення життєвого циклу. | Події activity додатково містять: @@ -69,6 +69,8 @@ Event::listen(WorkflowCompleted::class, function (WorkflowCompleted $event) { Надсилається, коли запуск workflow остаточно завершується з помилкою. +Перевищення часу виконання запуску також спричиняє `WorkflowFailed`. Натомість сплив строку очищення під час кооперативного скасування спричиняє `WorkflowCancelled`. + Додаткові поля: - `exceptionClass`: назва PHP-класу винятку. - `message`: повідомлення винятку. @@ -85,6 +87,49 @@ Event::listen(WorkflowFailed::class, function (WorkflowFailed $event) { }); ``` +### WorkflowCancelled {#workflowcancelled} + +Надсилається, коли негайне скасування закриває запуск або коли кооперативне скасування закриває його після завершення очищення чи спливу його строку. Сам запит на скасування не спричиняє цю подію. + +Окрім спільних полів ідентичності: + +| Поле | Опис | +|---|---| +| `reason` | Початкова причина з команди скасування або `null`. Повідомлення про завершення очищення та сплив його строку не замінюють її. | +| `closedAt` | Збережений час закриття запуску як рядок ISO 8601 у 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} + +Надсилається, коли примусове завершення закриває запуск. Містить ті самі поля ідентичності, `reason` і `closedAt`; причину взято з команди примусового завершення. Код очищення 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, + ]); +}); +``` + +Це сповіщення Laravel у межах процесу. Помилка слухача не може скасувати зафіксоване закриття. Події не надають права відновлювати закритий запуск і не гарантують стійкої доставки до зовнішньої системи. + ## Події activity {#activity-events} ### ActivityStarted {#activitystarted} @@ -165,13 +210,13 @@ Event::listen(FailureRecorded::class, function (FailureRecorded $event) { ## Семантика часових позначок {#timestamp-semantics} -Поле `committedAt` усіх подій означає **час фіксації**: реальний час запису стійкого запису (події історії чи запису помилки) до бази даних. Він відрізняється від: +Рушій фіксує `committedAt` під час підготовки сповіщення життєвого циклу. Це позначка реального годинника, яка відрізняється від: - **Віртуального часу workflow**: логічного часу всередині виконання workflow, який використовують timer. - **Часу спроби**: коли конкретна спроба activity почалася чи завершилася. - **Затримки відновлення**: скільки часу минуло після запланованого спрацювання timer до фактичного продовження workflow. -Час фіксації найкорисніший для зовнішніх інтеграцій, бо відображає момент, коли стан став стійким і доступним для спостереження. +Для скасування та примусового завершення `closedAt` — це збережена часова позначка закриття запуску в UTC. Зовнішня транзакція сховища може зафіксуватися пізніше, ніж було знято значення полів події. Вимірюючи затримку доставки, окремо записуйте час отримання події слухачем. ## Життєвий цикл {#lifecycle} @@ -195,6 +240,22 @@ Workflow\V2\Events\WorkflowFailed Workflow\V2\Events\FailureRecorded (source: workflow_run) ``` +Скасований запуск закінчується так: + +``` +Workflow\V2\Events\WorkflowStarted +Workflow\V2\Events\WorkflowCancelled +``` + +Між цими двома сповіщеннями кооперативне очищення може спричиняти події activity. + +Примусово завершений запуск закінчується так: + +``` +Workflow\V2\Events\WorkflowStarted +Workflow\V2\Events\WorkflowTerminated +``` + ## Простір імен подій {#event-namespace} Події V2 розміщено в просторі імен `Workflow\V2\Events`. Якщо оновлюєте наявний застосунок, дивіться [міграцію](../migration.md) для зіставлення сумісних подій V1. diff --git a/i18n/uk/source-hashes.json b/i18n/uk/source-hashes.json index ba519e457c8..66bd757583f 100644 --- a/i18n/uk/source-hashes.json +++ b/i18n/uk/source-hashes.json @@ -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", diff --git a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/features/events.md b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/features/events.md index f7cfa1c1c33..cf8dce0047c 100644 --- a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/features/events.md +++ b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/features/events.md @@ -6,7 +6,7 @@ sidebar_position: 12 生命周期事件在工作流和活动执行的关键阶段派发,向应用通知进度、完成或故障。这些是标准 Laravel 事件,可在 `EventServiceProvider` 中或通过 `Event::listen()` 注册监听器。 -所有 v2 生命周期事件均在**持久状态提交到数据库之后**派发。监听器只能观察由已提交事实支持的事件;事务回滚时不会派发事件。 +`WorkflowCancelled` 和 `WorkflowTerminated` 会等待运行所用存储连接上的事务提交。被拒绝的命令和已回滚的存储写入均不会派发这两种事件。引擎事务及生命周期事件顺序的其他问题仍由 [workflow#893](https://github.com/durable-workflow/workflow/issues/893) 跟踪。应用在另一数据库上开启的事务不会使工作流存储写入具有原子性。 ## 事件标识 {#event-identity} @@ -18,7 +18,7 @@ sidebar_position: 12 | `runId` | 具体执行的运行 ID。 | | `workflowType` | 通过 `#[Type('...')]` 注册的持久类型键。 | | `workflowClass` | 工作流的 PHP 类名。 | -| `committedAt` | 持久记录提交时的 ISO 8601 时间戳,即系统时钟提交时间。 | +| `committedAt` | 准备生命周期通知时记录的系统时钟时间戳,格式为 ISO 8601。 | 活动事件还包括: @@ -69,6 +69,8 @@ Event::listen(WorkflowCompleted::class, function (WorkflowCompleted $event) { 工作流运行发生终态失败时派发。 +运行超时也会派发 `WorkflowFailed`。协作取消的清理期限到期时则派发 `WorkflowCancelled`。 + 附加字段: - `exceptionClass`:PHP 异常类名。 @@ -86,6 +88,49 @@ Event::listen(WorkflowFailed::class, function (WorkflowFailed $event) { }); ``` +### WorkflowCancelled {#workflowcancelled} + +立即取消关闭运行时,或协作取消在清理完成或清理期限到期后关闭运行时派发。仅发出取消请求不会派发此事件。 + +除通用标识字段外,还包括: + +| 字段 | 说明 | +|---|---| +| `reason` | 取消命令的原始原因,或 `null`。清理完成或期限到期的消息不会覆盖它。 | +| `closedAt` | 已持久保存的运行关闭时间,表示为 UTC ISO 8601 字符串。 | + +```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} + +终止操作关闭运行时派发。它携带相同的标识字段、`reason` 和 `closedAt`,原因取自终止命令。终止操作不执行工作流清理代码。 + +```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, + ]); +}); +``` + +这些是在进程内派发的 Laravel 通知。监听器失败无法撤销已提交的关闭操作。这些事件不授予恢复已关闭运行的权限,也不保证向外部系统持久投递。 + ## 活动事件 {#activity-events} ### ActivityStarted {#activitystarted} @@ -167,13 +212,13 @@ Event::listen(FailureRecorded::class, function (FailureRecorded $event) { ## 时间戳语义 {#timestamp-semantics} -所有事件的 `committedAt` 表示**提交时间**,即持久记录(历史事件或故障记录)写入数据库时的系统时钟时间。它不同于: +引擎在准备生命周期通知时记录 `committedAt`。这是系统时钟时间戳,与以下时间不同: - **工作流虚拟时间**:工作流执行内部的逻辑时间,供定时器使用。 - **尝试时间**:某次具体活动尝试开始或结束的时间。 - **恢复延迟**:定时器到期至工作流实际恢复之间的时长。 -提交时间最适合外部集成,因为它反映状态何时变为持久且可观察。 +对于取消和终止,`closedAt` 是以 UTC 表示的、已持久保存的运行关闭时间戳。外层存储事务可能在事件字段记录之后才提交。测量投递延迟时,应单独记录监听器接收时间。 ## 生命周期 {#lifecycle} @@ -197,6 +242,22 @@ Workflow\V2\Events\WorkflowFailed Workflow\V2\Events\FailureRecorded (source: workflow_run) ``` +被取消的运行以以下事件结束: + +``` +Workflow\V2\Events\WorkflowStarted +Workflow\V2\Events\WorkflowCancelled +``` + +协作清理可以在这两条通知之间派发活动事件。 + +被终止的运行以以下事件结束: + +``` +Workflow\V2\Events\WorkflowStarted +Workflow\V2\Events\WorkflowTerminated +``` + ## 事件命名空间 {#event-namespace} v2 事件位于 `Workflow\V2\Events` 命名空间。升级已有应用时,v1 兼容事件映射见[迁移](../migration.md)。 diff --git a/i18n/zh-Hans/source-hashes.json b/i18n/zh-Hans/source-hashes.json index ba519e457c8..66bd757583f 100644 --- a/i18n/zh-Hans/source-hashes.json +++ b/i18n/zh-Hans/source-hashes.json @@ -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", diff --git a/static/stable-releases.json b/static/stable-releases.json index 5981f94cd80..3084755d660 100644 --- a/static/stable-releases.json +++ b/static/stable-releases.json @@ -1,7 +1,7 @@ { "schema": "durable-workflow.docs.stable-releases", "schema_version": 1, - "updated_at": "2026-10-23", + "updated_at": "2026-10-26", "artifacts": { "cli": "2.3.0", "helm-chart": "0.2.3", @@ -10,7 +10,7 @@ "sdk-rust": "4.2.0", "server": "2.10.1", "waterline": "2.12.1", - "workflow": "2.11.0" + "workflow": "2.15.0" }, "helm_chart": { "app_version": "2.10.1",