From 7a4f6a6d74e80f07258f63cc81394c30622a4da7 Mon Sep 17 00:00:00 2001 From: Richard McDaniel <1130888+rmcdaniel@users.noreply.github.com> Date: Wed, 4 Nov 2026 08:23:00 -0600 Subject: [PATCH] docs: adopt Workflow 2.20.3 stream replay guidance --- docs/features/message-streams.md | 45 ++++++++++++--- docs/testing.md | 8 +++ .../current/features/message-streams.md | 55 ++++++++++++++++--- .../current/testing.md | 9 +++ i18n/de/source-hashes.json | 4 +- .../current/features/message-streams.md | 50 ++++++++++++++--- .../current/testing.md | 10 ++++ i18n/es/source-hashes.json | 4 +- .../current/features/message-streams.md | 54 +++++++++++++++--- .../current/testing.md | 9 +++ i18n/fr/source-hashes.json | 4 +- .../current/features/message-streams.md | 41 +++++++++++++- .../current/testing.md | 7 +++ i18n/ja/source-hashes.json | 4 +- .../current/features/message-streams.md | 51 ++++++++++++++--- .../current/testing.md | 9 +++ i18n/pt-BR/source-hashes.json | 4 +- .../current/features/message-streams.md | 48 +++++++++++++--- .../current/testing.md | 9 +++ i18n/uk/source-hashes.json | 4 +- .../current/features/message-streams.md | 34 +++++++++++- .../current/testing.md | 6 ++ i18n/zh-Hans/source-hashes.json | 4 +- static/stable-releases.json | 2 +- 24 files changed, 406 insertions(+), 69 deletions(-) diff --git a/docs/features/message-streams.md b/docs/features/message-streams.md index ca876846c81..b1ba3376fa2 100644 --- a/docs/features/message-streams.md +++ b/docs/features/message-streams.md @@ -36,29 +36,60 @@ Do not write `workflow_messages` rows or cursor rows directly from application workflow code. The facade is the stable contract; lower-level message services exist for package/runtime integration. -:::warning Message streams in Workflow 2.20.0 and earlier +:::warning Message streams before Workflow 2.20.3 Workflow code replays on every later workflow task and on every query. In Workflow releases through 2.20.0, `outbox()->sendReference()` writes a new outbound and inbound message on each replay, and `inbox()->receive()` and `receiveOne()` can return a different message, or none, on replay ([workflow#1010](https://github.com/durable-workflow/workflow/issues/1010)). -Workflow 2.20.1 fixes this: a replay returns what the original call sent or -received, and a query never writes or consumes a message. +Workflow 2.20.1 records sends and receives for replay and prevents queries +from writing or consuming messages. Empty receives and streams kept across +steps need the additional replay fixes in 2.20.3, described below. - Rows that earlier releases duplicated are not removed. Give each logical send a stable `idempotencyKey`, such as `reply:{turn}`, and deduplicate by `idempotency_key` when consuming a stream that an earlier release wrote. Messages that an earlier release consumed under the wrong step stay consumed. -- In every release, signals and all streams share one message cursor, so a - signal delivered after a pending stream message hides that message +- Signals, updates and all streams share one message cursor. Through 2.20.2, + a signal, update or receive on another stream can move it past pending + messages and hide them ([workflow#1011](https://github.com/durable-workflow/workflow/issues/1011)). - Receive only after a signal or condition says a message is there, and send - that signal before the message. + For the signal-ordering case on those releases, send the signal before the + message and receive only after a signal or condition says a message is there. ::: +## Stream upgrades and rollback {#stream-upgrades} + +In Workflow 2.20.3, the shared cursor no longer hides pending messages from +`receive()`, `receiveOne()`, `peek()`, `pendingCount()` or `hasPending()`. +Receives keep sequence order and their batch limit. After upgrading, a receive +loop can return older pending messages that the shared cursor previously hid, +before newer messages. + +A replayed receive returns what its original step consumed. If the original +call found nothing, replay returns nothing again. An update handler running +for the first time can still receive. A stream kept in a property now records +receives at the current workflow step, rather than the step where the stream +was opened. Receives that earlier releases recorded at the opening step still +replay. + +Before rolling an embedded application back below 2.20.3, follow the +[replay testing gate](../testing.md#replay-before-deployment) with histories +written by the newer package. Earlier versions look up kept-stream receives +at the opening step and can replay those runs differently. Rollback also +restores the shared-cursor, empty-receive replay and fake task-drain precision +bugs. See the [tagged compatibility notes](https://github.com/durable-workflow/workflow/blob/2.20.3/CHANGELOG.md#2203---2026-11-04). + +The query limitation in +[workflow#1024](https://github.com/durable-workflow/workflow/issues/1024) +remains: a query can return nothing for a message an update handler received +because it replays the handler at the wrong step. The query changes no message +rows. The workflow's own replay and completed output still return what the +handler received. + ## Receiving Messages Use `peek()` when a workflow needs to inspect pending inbound messages without diff --git a/docs/testing.md b/docs/testing.md index 8160e2130e2..790a4195b85 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -173,6 +173,14 @@ public function testTimerWorkflow(): void `WorkflowStub::runReadyTasks()` only drains tasks that are already due. It does not fast-forward wall clock time or force future-delayed timers to fire early. +Workflow 2.20.3 drains fake tasks at their exact due time, including fractional +seconds, using the configured task model's persisted timestamp precision. +Earlier versions could skip SQLite tasks due at that instant. A future +fractional deadline stays pending until it is due. Timer delays and retry +backoff still use whole seconds. See the +[stream upgrade and rollback limits](./features/message-streams.md#stream-upgrades) +before rolling an embedded application back to an older package. + ### Sending Signals in Fake Mode Signal-waiting workflows can receive signals in fake mode. When you call `$workflow->signal(...)`, the engine records the durable signal command and creates a workflow task. In fake mode that task executes inline, so the workflow resumes synchronously: diff --git a/i18n/de/docusaurus-plugin-content-docs/current/features/message-streams.md b/i18n/de/docusaurus-plugin-content-docs/current/features/message-streams.md index 13d1388f657..aeb5bac2e3d 100644 --- a/i18n/de/docusaurus-plugin-content-docs/current/features/message-streams.md +++ b/i18n/de/docusaurus-plugin-content-docs/current/features/message-streams.md @@ -38,7 +38,7 @@ Schreiben Sie aus Workflow-Code der Anwendung keine `workflow_messages`- oder Cursor-Zeilen direkt. Die Fassade ist der stabile Vertrag. Niedrigere Nachrichtendienste existieren für die Paket-/Laufzeitintegration. -:::warning Nachrichtenströme in Workflow 2.20.0 und früher +:::warning Nachrichtenströme vor Workflow 2.20.3 Workflow-Code wird bei jeder späteren Workflow-Aufgabe und bei jeder Abfrage erneut abgespielt (Replay). In Workflow-Releases bis einschließlich 2.20.0 @@ -46,9 +46,10 @@ schreibt `outbox()->sendReference()` bei jedem Replay eine neue ausgehende und eingehende Nachricht, und `inbox()->receive()` und `receiveOne()` können beim Replay eine andere Nachricht oder gar keine zurückgeben ([workflow#1010](https://github.com/durable-workflow/workflow/issues/1010)). -Workflow 2.20.1 behebt dies: Ein Replay gibt zurück, was der ursprüngliche -Aufruf gesendet oder empfangen hat, und eine Abfrage schreibt oder verbraucht -niemals eine Nachricht. +Workflow 2.20.1 zeichnet Sendevorgänge und Empfangsvorgänge für das Replay auf +und verhindert, dass Abfragen Nachrichten schreiben oder verbrauchen. Leere +Empfangsaufrufe und über Schritte hinweg aufbewahrte Ströme benötigen die +weiteren Replay-Korrekturen aus 2.20.3, die unten beschrieben werden. - Zeilen, die frühere Releases dupliziert haben, werden nicht entfernt. Geben Sie jedem logischen Sendevorgang einen stabilen `idempotencyKey`, etwa @@ -56,15 +57,51 @@ niemals eine Nachricht. wenn Sie einen Strom verarbeiten, den ein früheres Release geschrieben hat. Nachrichten, die ein früheres Release unter dem falschen Schritt verbraucht hat, bleiben verbraucht. -- In jedem Release teilen sich Signale und alle Ströme einen gemeinsamen - Nachrichten-Cursor. Ein Signal, das nach einer ausstehenden Stromnachricht - zugestellt wird, verbirgt daher diese Nachricht +- Signale, Updates und alle Ströme teilen sich einen Nachrichten-Cursor. + Bis einschließlich 2.20.2 können ein Signal, ein Update oder ein Empfang + in einem anderen Strom ihn über ausstehende Nachrichten hinaus verschieben + und sie verbergen ([workflow#1011](https://github.com/durable-workflow/workflow/issues/1011)). - Empfangen Sie erst, nachdem ein Signal oder eine Bedingung anzeigt, dass eine - Nachricht vorhanden ist, und senden Sie dieses Signal vor der Nachricht. + Senden Sie für diesen Fall der Signalreihenfolge in diesen Versionen das + Signal vor der Nachricht und empfangen Sie erst, nachdem ein Signal oder + eine Bedingung anzeigt, dass eine Nachricht vorhanden ist. ::: +## Upgrades und Rollbacks von Nachrichtenströmen {#stream-upgrades} + +In Workflow 2.20.3 verbirgt der gemeinsame Cursor keine ausstehenden Nachrichten +mehr vor `receive()`, `receiveOne()`, `peek()`, `pendingCount()` oder +`hasPending()`. Empfangsvorgänge behalten Sequenzreihenfolge und Stapelgrenze +bei. Nach dem Upgrade kann eine Empfangsschleife zuerst ältere ausstehende +Nachrichten zurückgeben, die der gemeinsame Cursor bisher verborgen hat, und +danach neuere Nachrichten. + +Ein Empfang beim Replay gibt zurück, was sein ursprünglicher Schritt +verbraucht hat. Hat der ursprüngliche Aufruf nichts gefunden, gibt auch das +Replay nichts zurück. Ein erstmals ausgeführter Update-Handler kann weiterhin +empfangen. Ein in einer Eigenschaft aufbewahrter Strom zeichnet Empfang nun +beim aktuellen Workflow-Schritt auf, statt beim Schritt, in dem er geöffnet +wurde. Empfangsvorgänge, die frühere Releases beim Öffnungsschritt aufgezeichnet +haben, lassen sich weiterhin per Replay ausführen. + +Bevor Sie eine eingebettete Anwendung auf eine Version vor 2.20.3 zurücksetzen, +wenden Sie die [Replay-Prüfung](../testing.md#replay-before-deployment) auf +Verläufe an, die das neuere Paket geschrieben hat. Frühere Versionen suchen +den Empfang aufbewahrter Ströme beim Öffnungsschritt und können solche Läufe +anders wiedergeben. Ein Rollback stellt außerdem die Fehler beim gemeinsamen +Cursor, beim Replay leerer Empfangsaufrufe und bei der Genauigkeit der +Fake-Aufgabenverarbeitung wieder her. Siehe die +[Kompatibilitätshinweise zum Tag](https://github.com/durable-workflow/workflow/blob/2.20.3/CHANGELOG.md#2203---2026-11-04). + +Die Abfrageeinschränkung in +[workflow#1024](https://github.com/durable-workflow/workflow/issues/1024) +bleibt bestehen: Eine Abfrage kann für eine von einem Update-Handler empfangene +Nachricht nichts zurückgeben, weil sie den Handler beim falschen Schritt +wiedergibt. Die Abfrage ändert keine Nachrichtenzeilen. Beim eigenen Replay +des Workflows und in seiner abgeschlossenen Ausgabe wird weiterhin +zurückgegeben, was der Handler empfangen hat. + ## Nachrichten empfangen {#receiving-messages} Verwenden Sie `peek()`, wenn ein Workflow ausstehende eingehende Nachrichten diff --git a/i18n/de/docusaurus-plugin-content-docs/current/testing.md b/i18n/de/docusaurus-plugin-content-docs/current/testing.md index 39aae015dde..4e2d869bbeb 100644 --- a/i18n/de/docusaurus-plugin-content-docs/current/testing.md +++ b/i18n/de/docusaurus-plugin-content-docs/current/testing.md @@ -174,6 +174,15 @@ public function testTimerWorkflow(): void `WorkflowStub::runReadyTasks()` arbeitet nur bereits fällige Aufgaben ab. Es stellt die reale Uhrzeit nicht vor und löst künftig verzögerte Timer nicht vorzeitig aus. +Workflow 2.20.3 verarbeitet Fake-Aufgaben exakt zur Fälligkeit, einschließlich +Sekundenbruchteilen, mit der gespeicherten Zeitstempelgenauigkeit des +konfigurierten Aufgabenmodells. Frühere Versionen konnten SQLite-Aufgaben +überspringen, die genau zu diesem Zeitpunkt fällig wurden. Eine künftige +Fälligkeit mit Sekundenbruchteilen bleibt bis zu ihrem Eintreten ausstehend. +Timerverzögerungen und Wiederholungs-Backoff bleiben in ganzen Sekunden. +Beachten Sie die [Grenzen für Upgrades und Rollbacks von Nachrichtenströmen](./features/message-streams.md#stream-upgrades), +bevor Sie eine eingebettete Anwendung auf ein älteres Paket zurücksetzen. + ### Signale im Fake-Modus senden {#sending-signals-in-fake-mode} Workflows, die auf Signale warten, können diese im Fake-Modus empfangen. Beim Aufruf von `$workflow->signal(...)` zeichnet die Engine den dauerhaften Signalbefehl auf und erstellt eine Workflow-Aufgabe. Im Fake-Modus wird diese direkt ausgeführt, sodass der Workflow synchron fortsetzt: diff --git a/i18n/de/source-hashes.json b/i18n/de/source-hashes.json index c8810e96662..d93da79ef10 100644 --- a/i18n/de/source-hashes.json +++ b/i18n/de/source-hashes.json @@ -41,7 +41,7 @@ "features/heartbeats.md": "e3d84178788dff92954e08d08f006def0a991a481f99301facbda8c6ca21a7a0", "features/local-activities.md": "05fca8f2104d8f4e7bd8b48040f5615f18d0ee2795922fb65c56f8d3d70ed204", "features/memo.md": "621aa630e37fbef6f84d761c92f99dc3fe8756879008c659cbad0600eb14fd5d", - "features/message-streams.md": "b30c7629d3fb9d20f27c4bcf0551457d65ac44a541b119312a2cde31aba48354", + "features/message-streams.md": "8a21b2e6dff51c69a3395d50ea6167e418ed793b4b7107b964f2a0f5f03a3801", "features/queries.md": "c66dd9542a062edd8158a46cebc9f1bf926aaf3599dca4a3122bd9860df6e2a2", "features/sagas.md": "8dae955491a54bcbf545ce6972928df59f3885e00f98bf3a57b14dad98f89161", "features/schedules.md": "717b9115ca62a69a3a1ea65f1bec68a0aebe0d5e6d2421df297bb129c597a523", @@ -104,6 +104,6 @@ "sdk-neutrality.md": "7b0714c123ade4904591870fc20e9a797da1e5485b2a6c87ca3eaa00c5de6ed6", "sponsors.md": "e85e14375743ca8fa50e3a48f894b160e28272573aa88480064f74010ebee98a", "support.md": "706807b3902599dda6080f632ec1f893017ea18bbe9585f533dcdbd6d85f4621", - "testing.md": "b80db83e74647e9559c1f0db442dcfe7c0e636d8c9842583c69f9ae46d68633d", + "testing.md": "250bc7dfd46f99eaeb392b329947813b064bda72026645198e3aefc80043a813", "waterline-operator-api.md": "2aca03b2c14100060b40be0bb033a82525ba924908834e9060ec746ead26f36d" } diff --git a/i18n/es/docusaurus-plugin-content-docs/current/features/message-streams.md b/i18n/es/docusaurus-plugin-content-docs/current/features/message-streams.md index 9c3a4873d7e..9cc80f8697e 100644 --- a/i18n/es/docusaurus-plugin-content-docs/current/features/message-streams.md +++ b/i18n/es/docusaurus-plugin-content-docs/current/features/message-streams.md @@ -28,29 +28,65 @@ Usa la fachada de primera clase al escribir workflows: No escribas directamente filas `workflow_messages` ni de cursor desde el workflow de la aplicación. La fachada es el contrato estable; los servicios de nivel inferior existen para integrar paquete y runtime. -:::warning Flujos de mensajes en Workflow 2.20.0 y versiones anteriores +:::warning Flujos de mensajes anteriores a Workflow 2.20.3 El código del workflow se reproduce en cada tarea de workflow posterior y en cada consulta. En las versiones de Workflow hasta la 2.20.0 inclusive, `outbox()->sendReference()` escribe un nuevo mensaje saliente y entrante en cada reproducción, e `inbox()->receive()` y `receiveOne()` pueden devolver un mensaje distinto, o ninguno, en la reproducción ([workflow#1010](https://github.com/durable-workflow/workflow/issues/1010)). -Workflow 2.20.1 lo corrige: una reproducción devuelve lo que la llamada original envió o -recibió, y una consulta nunca escribe ni consume un mensaje. +Workflow 2.20.1 registra los envíos y las recepciones para la reproducción e +impide que las consultas escriban o consuman mensajes. Las recepciones vacías +y los flujos conservados entre pasos necesitan las correcciones adicionales +de reproducción de 2.20.3 que se describen a continuación. - Las filas que las versiones anteriores duplicaron no se eliminan. Da a cada envío lógico un `idempotencyKey` estable, como `reply:{turn}`, y deduplica por `idempotency_key` al consumir un flujo que escribió una versión anterior. Los mensajes que una versión anterior consumió en el paso equivocado siguen consumidos. -- En todas las versiones, las señales y todos los flujos comparten un único cursor de mensajes, por lo que - una señal entregada después de un mensaje pendiente de un flujo oculta ese mensaje +- Las señales, las actualizaciones y todos los flujos comparten un cursor de + mensajes. Hasta 2.20.2 inclusive, una señal, una actualización o una recepción + en otro flujo puede moverlo más allá de los mensajes pendientes y ocultarlos ([workflow#1011](https://github.com/durable-workflow/workflow/issues/1011)). - Recibe solo después de que una señal o una condición indique que hay un mensaje, y envía - esa señal antes del mensaje. + Para ese caso de orden de señales en esas versiones, envía la señal antes + del mensaje y recibe solo después de que una señal o condición indique que + hay un mensaje. ::: +## Actualizaciones de flujos y reversión {#stream-upgrades} + +En Workflow 2.20.3, el cursor compartido ya no oculta mensajes pendientes a +`receive()`, `receiveOne()`, `peek()`, `pendingCount()` ni `hasPending()`. Las +recepciones mantienen el orden de secuencia y su límite de lote. Tras +actualizar, un bucle de recepción puede devolver primero mensajes pendientes +antiguos que el cursor compartido ocultaba y después los más recientes. + +Una recepción reproducida devuelve lo que consumió su paso original. Si la +llamada original no encontró nada, la reproducción tampoco devuelve nada. +Un manejador de actualización que se ejecuta por primera vez sigue pudiendo +recibir. Un flujo conservado en una propiedad ahora registra las recepciones +en el paso actual del workflow, en lugar del paso en que se abrió el flujo. +Las recepciones que versiones anteriores registraron en el paso de apertura +siguen reproduciéndose. + +Antes de revertir una aplicación integrada a una versión anterior a 2.20.3, +aplica el [control de reproducción](../testing.md#replay-before-deployment) +con historiales escritos por el paquete más reciente. Las versiones +anteriores buscan las recepciones de un flujo conservado en el paso de +apertura y pueden reproducir esas ejecuciones de otra manera. La reversión +también restaura los errores del cursor compartido, la reproducción de +recepciones vacías y la precisión del procesamiento de tareas fake. Consulta las +[notas de compatibilidad de la etiqueta](https://github.com/durable-workflow/workflow/blob/2.20.3/CHANGELOG.md#2203---2026-11-04). + +La limitación de consultas en +[workflow#1024](https://github.com/durable-workflow/workflow/issues/1024) +permanece: una consulta puede no devolver un mensaje que recibió un manejador +de actualización porque reproduce el manejador en el paso equivocado. La +consulta no cambia filas de mensajes. La reproducción del propio workflow y +su salida completada siguen devolviendo lo que recibió el manejador. + ## Recibir mensajes {#receiving-messages} Usa `peek()` para inspeccionar mensajes pendientes sin avanzar el cursor duradero. Usa `receive()` o `receiveOne()` cuando estés listo para consumirlos y registrar el avance en el historial. diff --git a/i18n/es/docusaurus-plugin-content-docs/current/testing.md b/i18n/es/docusaurus-plugin-content-docs/current/testing.md index d80e6012eab..a7b3400261f 100644 --- a/i18n/es/docusaurus-plugin-content-docs/current/testing.md +++ b/i18n/es/docusaurus-plugin-content-docs/current/testing.md @@ -175,6 +175,16 @@ public function testTimerWorkflow(): void `WorkflowStub::runReadyTasks()` solo ejecuta tareas cuyo plazo ya llegó. No adelanta el reloj ni fuerza la activación anticipada de temporizadores futuros. +Workflow 2.20.3 procesa las tareas fake en su instante exacto de vencimiento, +incluidas las fracciones de segundo, con la precisión de marcas temporales +que persiste el modelo de tareas configurado. Las versiones anteriores +podían omitir tareas de SQLite que vencían en ese instante. Un plazo futuro +con fracciones de segundo permanece pendiente hasta su vencimiento. Los +retrasos de temporizador y el backoff de reintento siguen usando segundos +enteros. Consulta los +[límites de actualización y reversión de flujos](./features/message-streams.md#stream-upgrades) +antes de revertir una aplicación integrada a un paquete anterior. + ### Enviar señales en modo simulado {#sending-signals-in-fake-mode} Los workflows que esperan señales pueden recibirlas en modo simulado. Al llamar a `$workflow->signal(...)`, el motor registra el comando duradero y crea una tarea de workflow. Esa tarea se ejecuta inmediatamente en modo simulado y el workflow se reanuda de forma síncrona: diff --git a/i18n/es/source-hashes.json b/i18n/es/source-hashes.json index c8810e96662..d93da79ef10 100644 --- a/i18n/es/source-hashes.json +++ b/i18n/es/source-hashes.json @@ -41,7 +41,7 @@ "features/heartbeats.md": "e3d84178788dff92954e08d08f006def0a991a481f99301facbda8c6ca21a7a0", "features/local-activities.md": "05fca8f2104d8f4e7bd8b48040f5615f18d0ee2795922fb65c56f8d3d70ed204", "features/memo.md": "621aa630e37fbef6f84d761c92f99dc3fe8756879008c659cbad0600eb14fd5d", - "features/message-streams.md": "b30c7629d3fb9d20f27c4bcf0551457d65ac44a541b119312a2cde31aba48354", + "features/message-streams.md": "8a21b2e6dff51c69a3395d50ea6167e418ed793b4b7107b964f2a0f5f03a3801", "features/queries.md": "c66dd9542a062edd8158a46cebc9f1bf926aaf3599dca4a3122bd9860df6e2a2", "features/sagas.md": "8dae955491a54bcbf545ce6972928df59f3885e00f98bf3a57b14dad98f89161", "features/schedules.md": "717b9115ca62a69a3a1ea65f1bec68a0aebe0d5e6d2421df297bb129c597a523", @@ -104,6 +104,6 @@ "sdk-neutrality.md": "7b0714c123ade4904591870fc20e9a797da1e5485b2a6c87ca3eaa00c5de6ed6", "sponsors.md": "e85e14375743ca8fa50e3a48f894b160e28272573aa88480064f74010ebee98a", "support.md": "706807b3902599dda6080f632ec1f893017ea18bbe9585f533dcdbd6d85f4621", - "testing.md": "b80db83e74647e9559c1f0db442dcfe7c0e636d8c9842583c69f9ae46d68633d", + "testing.md": "250bc7dfd46f99eaeb392b329947813b064bda72026645198e3aefc80043a813", "waterline-operator-api.md": "2aca03b2c14100060b40be0bb033a82525ba924908834e9060ec746ead26f36d" } diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/features/message-streams.md b/i18n/fr/docusaurus-plugin-content-docs/current/features/message-streams.md index 83b0453adc4..a38231521a3 100644 --- a/i18n/fr/docusaurus-plugin-content-docs/current/features/message-streams.md +++ b/i18n/fr/docusaurus-plugin-content-docs/current/features/message-streams.md @@ -38,7 +38,7 @@ N’écrivez pas directement les lignes `workflow_messages` ou de curseur depuis le code applicatif du workflow. La façade est le contrat stable. Les services de messages de bas niveau servent à l’intégration du package et du runtime. -:::warning Flux de messages dans Workflow 2.20.0 et versions antérieures +:::warning Flux de messages avant Workflow 2.20.3 Le code de workflow est relu à chaque tâche de workflow ultérieure et à chaque requête de lecture. Dans les versions de Workflow jusqu’à 2.20.0 incluse, @@ -46,24 +46,60 @@ requête de lecture. Dans les versions de Workflow jusqu’à 2.20.0 incluse, message entrant à chaque relecture, et `inbox()->receive()` et `receiveOne()` peuvent renvoyer un autre message, ou aucun, lors de la relecture ([workflow#1010](https://github.com/durable-workflow/workflow/issues/1010)). -Workflow 2.20.1 corrige ce problème : une relecture renvoie ce que l’appel -d’origine a envoyé ou reçu, et une requête de lecture n’écrit ni ne consomme -jamais de message. +Workflow 2.20.1 enregistre les envois et réceptions pour la relecture et empêche +les requêtes de lecture d’écrire ou de consommer des messages. Les réceptions +vides et les flux conservés entre les étapes nécessitent les corrections +supplémentaires de relecture de 2.20.3 décrites ci-dessous. - Les lignes dupliquées par les versions antérieures ne sont pas supprimées. Donnez à chaque envoi logique un `idempotencyKey` stable, comme `reply:{turn}`, et dédupliquez par `idempotency_key` lors de la consommation d’un flux écrit par une version antérieure. Les messages qu’une version antérieure a consommés sous la mauvaise étape restent consommés. -- Dans toutes les versions, les signaux et tous les flux partagent un même - curseur de messages ; un signal livré après un message de flux en attente - masque donc ce message +- Les signaux, les mises à jour et tous les flux partagent un curseur de + messages. Jusqu’à 2.20.2 incluse, un signal, une mise à jour ou une réception + sur un autre flux peut le faire avancer au-delà des messages en attente et + les masquer ([workflow#1011](https://github.com/durable-workflow/workflow/issues/1011)). - Ne recevez qu’après qu’un signal ou une condition indique qu’un message est - présent, et envoyez ce signal avant le message. + Pour ce cas d’ordre des signaux dans ces versions, envoyez le signal avant + le message et ne recevez qu’après qu’un signal ou une condition indique + qu’un message est présent. ::: +## Mise à niveau des flux et retour en arrière {#stream-upgrades} + +Dans Workflow 2.20.3, le curseur partagé ne masque plus les messages en attente +à `receive()`, `receiveOne()`, `peek()`, `pendingCount()` ou `hasPending()`. +Les réceptions conservent l’ordre de séquence et leur limite de lot. Après la +mise à niveau, une boucle de réception peut renvoyer d’abord d’anciens messages +en attente que le curseur partagé masquait, puis les plus récents. + +Une réception relue renvoie ce que son étape d’origine a consommé. Si l’appel +d’origine n’a rien trouvé, la relecture ne renvoie de nouveau rien. Un +gestionnaire de mise à jour exécuté pour la première fois peut toujours +recevoir. Un flux conservé dans une propriété enregistre désormais les +réceptions à l’étape courante du workflow, plutôt qu’à celle où le flux a été +ouvert. Les réceptions que les anciennes versions ont enregistrées à l’étape +d’ouverture restent relisibles. + +Avant de ramener une application embarquée à une version antérieure à 2.20.3, +appliquez le [contrôle de relecture](../testing.md#replay-before-deployment) +aux historiques écrits par le paquet plus récent. Les anciennes versions +cherchent les réceptions des flux conservés à l’étape d’ouverture et peuvent +relire ces exécutions différemment. Le retour en arrière rétablit aussi les +défauts du curseur partagé, de relecture des réceptions vides et de précision +du traitement des tâches simulées. Consultez les +[notes de compatibilité du tag](https://github.com/durable-workflow/workflow/blob/2.20.3/CHANGELOG.md#2203---2026-11-04). + +La limite des requêtes de lecture dans +[workflow#1024](https://github.com/durable-workflow/workflow/issues/1024) +subsiste : une requête peut ne rien renvoyer pour un message reçu par un +gestionnaire de mise à jour, car elle relit celui-ci à la mauvaise étape. +La requête ne modifie aucune ligne de message. La relecture du workflow +lui-même et sa sortie après achèvement renvoient toujours ce que le +gestionnaire a reçu. + ## Recevoir des messages {#receiving-messages} Utilisez `peek()` pour inspecter les messages entrants en attente sans avancer diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/testing.md b/i18n/fr/docusaurus-plugin-content-docs/current/testing.md index c10b822d6c1..3bcdfe75336 100644 --- a/i18n/fr/docusaurus-plugin-content-docs/current/testing.md +++ b/i18n/fr/docusaurus-plugin-content-docs/current/testing.md @@ -184,6 +184,15 @@ public function testTimerWorkflow(): void `WorkflowStub::runReadyTasks()` ne traite que les tâches déjà échues. Il n'avance pas l'horloge réelle et ne déclenche pas prématurément les temporisateurs futurs. +Workflow 2.20.3 traite les tâches simulées à leur échéance exacte, y compris +les fractions de seconde, avec la précision des horodatages persistés par le +modèle de tâche configuré. Les anciennes versions pouvaient ignorer des +tâches SQLite arrivant à échéance à cet instant. Une échéance future avec une +fraction de seconde reste en attente jusqu’à son arrivée. Les délais de +temporisateur et le backoff de nouvelle tentative restent en secondes entières. +Consultez les [limites de mise à niveau des flux et de retour en arrière](./features/message-streams.md#stream-upgrades) +avant de revenir à un paquet antérieur dans une application embarquée. + ### Envoyer des signaux en mode simulé {#sending-signals-in-fake-mode} Les workflows en attente de signal peuvent en recevoir en mode simulé. À l'appel diff --git a/i18n/fr/source-hashes.json b/i18n/fr/source-hashes.json index c8810e96662..d93da79ef10 100644 --- a/i18n/fr/source-hashes.json +++ b/i18n/fr/source-hashes.json @@ -41,7 +41,7 @@ "features/heartbeats.md": "e3d84178788dff92954e08d08f006def0a991a481f99301facbda8c6ca21a7a0", "features/local-activities.md": "05fca8f2104d8f4e7bd8b48040f5615f18d0ee2795922fb65c56f8d3d70ed204", "features/memo.md": "621aa630e37fbef6f84d761c92f99dc3fe8756879008c659cbad0600eb14fd5d", - "features/message-streams.md": "b30c7629d3fb9d20f27c4bcf0551457d65ac44a541b119312a2cde31aba48354", + "features/message-streams.md": "8a21b2e6dff51c69a3395d50ea6167e418ed793b4b7107b964f2a0f5f03a3801", "features/queries.md": "c66dd9542a062edd8158a46cebc9f1bf926aaf3599dca4a3122bd9860df6e2a2", "features/sagas.md": "8dae955491a54bcbf545ce6972928df59f3885e00f98bf3a57b14dad98f89161", "features/schedules.md": "717b9115ca62a69a3a1ea65f1bec68a0aebe0d5e6d2421df297bb129c597a523", @@ -104,6 +104,6 @@ "sdk-neutrality.md": "7b0714c123ade4904591870fc20e9a797da1e5485b2a6c87ca3eaa00c5de6ed6", "sponsors.md": "e85e14375743ca8fa50e3a48f894b160e28272573aa88480064f74010ebee98a", "support.md": "706807b3902599dda6080f632ec1f893017ea18bbe9585f533dcdbd6d85f4621", - "testing.md": "b80db83e74647e9559c1f0db442dcfe7c0e636d8c9842583c69f9ae46d68633d", + "testing.md": "250bc7dfd46f99eaeb392b329947813b064bda72026645198e3aefc80043a813", "waterline-operator-api.md": "2aca03b2c14100060b40be0bb033a82525ba924908834e9060ec746ead26f36d" } diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/features/message-streams.md b/i18n/ja/docusaurus-plugin-content-docs/current/features/message-streams.md index f2ed4610692..8e50d34f808 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/features/message-streams.md +++ b/i18n/ja/docusaurus-plugin-content-docs/current/features/message-streams.md @@ -28,15 +28,50 @@ keywords: ワークフローコードから `workflow_messages` やカーソルの行を直接書き込まないでください。安定した契約はファサードです。下位のメッセージサービスはパッケージ・ランタイム統合用です。 -:::warning Workflow 2.20.0 以前のメッセージストリーム +:::warning Workflow 2.20.3 より前のメッセージストリーム -ワークフローコードは、後続のワークフロータスクのたびに、またクエリのたびにリプレイされます。Workflow 2.20.0 までのリリースでは、`outbox()->sendReference()` はリプレイのたびに送信メッセージと受信メッセージを新たに書き込み、`inbox()->receive()` と `receiveOne()` はリプレイ時に別のメッセージを返したり、何も返さなかったりすることがあります([workflow#1010](https://github.com/durable-workflow/workflow/issues/1010))。Workflow 2.20.1 でこれは修正されました。リプレイは元の呼び出しが送信または受信したものを返し、クエリがメッセージを書き込んだり消費したりすることはありません。 +ワークフローコードは、後続のワークフロータスクのたびに、またクエリのたびにリプレイされます。Workflow 2.20.0 までのリリースでは、`outbox()->sendReference()` はリプレイのたびに送信メッセージと受信メッセージを新たに書き込み、`inbox()->receive()` と `receiveOne()` はリプレイ時に別のメッセージを返したり、何も返さなかったりすることがあります([workflow#1010](https://github.com/durable-workflow/workflow/issues/1010))。Workflow 2.20.1 は送信と受信をリプレイ用に記録し、クエリによるメッセージの +書き込みや消費を防ぎます。空の受信と、ステップをまたいで保持したストリームには、 +以下で説明する 2.20.3 の追加のリプレイ修正が必要です。 - 以前のリリースで重複した行は削除されません。論理的な送信ごとに `reply:{turn}` のような安定した `idempotencyKey` を与え、以前のリリースが書き込んだストリームを消費するときは `idempotency_key` で重複を除いてください。以前のリリースが誤ったステップで消費したメッセージは、消費済みのままです。 -- どのリリースでも、シグナルとすべてのストリームは 1 つのメッセージカーソルを共有するため、保留中のストリームメッセージの後に届いたシグナルは、そのメッセージを隠してしまいます([workflow#1011](https://github.com/durable-workflow/workflow/issues/1011))。シグナルや条件がメッセージの存在を示した後でのみ受信し、そのシグナルはメッセージより前に送信してください。 +- シグナル、更新、すべてのストリームは一つのメッセージカーソルを共有します。 + 2.20.2 以前では、シグナル、更新、別のストリームでの受信によってカーソルが + 保留中のメッセージより先へ進み、それらを隠すことがあります + ([workflow#1011](https://github.com/durable-workflow/workflow/issues/1011))。 + これらのバージョンでのシグナル順序の問題には、メッセージより先にシグナルを + 送り、シグナルや条件がメッセージの存在を示した後でのみ受信してください。 ::: +## ストリームのアップグレードとロールバック {#stream-upgrades} + +Workflow 2.20.3 では、共有カーソルが `receive()`、`receiveOne()`、`peek()`、 +`pendingCount()`、`hasPending()` から保留メッセージを隠すことはなくなりました。 +受信は引き続き連番順とバッチの上限に従います。アップグレード後、受信ループは、 +共有カーソルが以前隠していた古い保留メッセージを、新しいメッセージより先に +返すことがあります。 + +リプレイ中の受信は、元のステップが消費した内容を返します。元の呼び出しが何も +見つけなかった場合、リプレイでも何も返しません。初めて実行される更新ハンドラーは +引き続き受信できます。プロパティに保持したストリームは、ストリームを開いた +ステップではなく、現在のワークフローステップで受信を記録するようになりました。 +以前のリリースでストリームを開いたステップに記録された受信も、引き続き +リプレイできます。 + +埋め込みアプリケーションを 2.20.3 より前のバージョンに戻す前に、新しいパッケージが +書き込んだ履歴で[リプレイテストの基準](../testing.md#replay-before-deployment)を +満たしてください。以前のバージョンは保持したストリームの受信を開いたステップで +検索するため、その実行のリプレイ結果が変わる可能性があります。ロールバックすると、 +共有カーソル、空の受信のリプレイ、fake タスク処理の精度の不具合も再発します。 +[タグの互換性に関する注記](https://github.com/durable-workflow/workflow/blob/2.20.3/CHANGELOG.md#2203---2026-11-04)を参照してください。 + +[workflow#1024](https://github.com/durable-workflow/workflow/issues/1024) のクエリ制限は +残っています。クエリはハンドラーを誤ったステップでリプレイするため、更新ハンドラーが +受信したメッセージに対して何も返さない場合があります。クエリはメッセージ行を +変更しません。ワークフロー自身のリプレイと完了時の出力は、引き続きハンドラーが +受信した内容を返します。 + ## メッセージの受信 {#receiving-messages} 永続カーソルを進めずに保留中の受信メッセージを調べるには `peek()` を使います。消費してカーソルの前進を履歴に記録する準備ができたら `receive()` または `receiveOne()` を使います。 diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/testing.md b/i18n/ja/docusaurus-plugin-content-docs/current/testing.md index 7fee383ed4a..8e3e2286333 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/testing.md +++ b/i18n/ja/docusaurus-plugin-content-docs/current/testing.md @@ -173,6 +173,13 @@ public function testTimerWorkflow(): void `WorkflowStub::runReadyTasks()` は期日到来済みのタスクだけを処理します。実時計を早送りしたり、将来の遅延タイマーを早く発火させたりはしません。 +Workflow 2.20.3 は、設定されたタスクモデルが永続化するタイムスタンプの精度で、 +小数秒を含む正確な期日に fake タスクを処理します。以前のバージョンでは、 +ちょうどその時点で期日を迎えた SQLite タスクを飛ばすことがありました。将来の +小数秒の期日は、その時刻まで保留されます。タイマーの遅延と再試行バックオフは +引き続き整数秒です。埋め込みアプリケーションを以前のパッケージへ戻す前に、 +[ストリームのアップグレードとロールバックの制限](./features/message-streams.md#stream-upgrades)を参照してください。 + ### fake モードでシグナルを送る {#sending-signals-in-fake-mode} シグナル待機中のワークフローも fake モードで受信できます。`$workflow->signal(...)` を呼ぶと、エンジンは永続シグナルコマンドを記録し、ワークフロータスクを作ります。fake モードではその場で実行するため、ワークフローは同期的に再開します。 diff --git a/i18n/ja/source-hashes.json b/i18n/ja/source-hashes.json index c8810e96662..d93da79ef10 100644 --- a/i18n/ja/source-hashes.json +++ b/i18n/ja/source-hashes.json @@ -41,7 +41,7 @@ "features/heartbeats.md": "e3d84178788dff92954e08d08f006def0a991a481f99301facbda8c6ca21a7a0", "features/local-activities.md": "05fca8f2104d8f4e7bd8b48040f5615f18d0ee2795922fb65c56f8d3d70ed204", "features/memo.md": "621aa630e37fbef6f84d761c92f99dc3fe8756879008c659cbad0600eb14fd5d", - "features/message-streams.md": "b30c7629d3fb9d20f27c4bcf0551457d65ac44a541b119312a2cde31aba48354", + "features/message-streams.md": "8a21b2e6dff51c69a3395d50ea6167e418ed793b4b7107b964f2a0f5f03a3801", "features/queries.md": "c66dd9542a062edd8158a46cebc9f1bf926aaf3599dca4a3122bd9860df6e2a2", "features/sagas.md": "8dae955491a54bcbf545ce6972928df59f3885e00f98bf3a57b14dad98f89161", "features/schedules.md": "717b9115ca62a69a3a1ea65f1bec68a0aebe0d5e6d2421df297bb129c597a523", @@ -104,6 +104,6 @@ "sdk-neutrality.md": "7b0714c123ade4904591870fc20e9a797da1e5485b2a6c87ca3eaa00c5de6ed6", "sponsors.md": "e85e14375743ca8fa50e3a48f894b160e28272573aa88480064f74010ebee98a", "support.md": "706807b3902599dda6080f632ec1f893017ea18bbe9585f533dcdbd6d85f4621", - "testing.md": "b80db83e74647e9559c1f0db442dcfe7c0e636d8c9842583c69f9ae46d68633d", + "testing.md": "250bc7dfd46f99eaeb392b329947813b064bda72026645198e3aefc80043a813", "waterline-operator-api.md": "2aca03b2c14100060b40be0bb033a82525ba924908834e9060ec746ead26f36d" } diff --git a/i18n/pt-BR/docusaurus-plugin-content-docs/current/features/message-streams.md b/i18n/pt-BR/docusaurus-plugin-content-docs/current/features/message-streams.md index 7c78b1cc521..25228c31143 100644 --- a/i18n/pt-BR/docusaurus-plugin-content-docs/current/features/message-streams.md +++ b/i18n/pt-BR/docusaurus-plugin-content-docs/current/features/message-streams.md @@ -37,7 +37,7 @@ Não grave linhas de `workflow_messages` ou de cursor diretamente pelo código de workflow da aplicação. A fachada é o contrato estável. Os serviços de mensagens de nível inferior existem para integração do pacote com o runtime. -:::warning Fluxos de mensagens no Workflow 2.20.0 e anteriores +:::warning Fluxos de mensagens anteriores ao Workflow 2.20.3 O código do workflow passa por replay em cada tarefa de workflow posterior e em cada consulta. Nas versões do Workflow até a 2.20.0, `outbox()->sendReference()` @@ -45,23 +45,58 @@ grava uma nova mensagem de saída e uma nova mensagem de entrada a cada replay, `inbox()->receive()` e `receiveOne()` podem retornar uma mensagem diferente, ou nenhuma, no replay ([workflow#1010](https://github.com/durable-workflow/workflow/issues/1010)). -O Workflow 2.20.1 corrige isso: um replay retorna o que a chamada original -enviou ou recebeu, e uma consulta nunca grava nem consome uma mensagem. +O Workflow 2.20.1 registra envios e recebimentos para replay e impede que +consultas gravem ou consumam mensagens. Recebimentos vazios e fluxos mantidos +entre etapas precisam das correções adicionais de replay da versão 2.20.3, +descritas abaixo. - As linhas que versões anteriores duplicaram não são removidas. Dê a cada envio lógico um `idempotencyKey` estável, como `reply:{turn}`, e elimine duplicatas por `idempotency_key` ao consumir um fluxo que uma versão anterior gravou. As mensagens que uma versão anterior consumiu sob a etapa errada permanecem consumidas. -- Em todas as versões, os sinais e todos os fluxos compartilham um único cursor - de mensagens, então um sinal entregue depois de uma mensagem de fluxo pendente - oculta essa mensagem +- Sinais, atualizações e todos os fluxos compartilham um cursor de mensagens. + Até a versão 2.20.2, um sinal, uma atualização ou um recebimento em outro + fluxo pode avançá-lo para além de mensagens pendentes e ocultá-las ([workflow#1011](https://github.com/durable-workflow/workflow/issues/1011)). - Receba somente depois que um sinal ou uma condição indicar que há uma mensagem, - e envie esse sinal antes da mensagem. + Para esse caso de ordenação de sinais nessas versões, envie o sinal antes + da mensagem e receba somente depois que um sinal ou condição indicar que há + uma mensagem. ::: +## Atualizações de fluxos e reversão {#stream-upgrades} + +No Workflow 2.20.3, o cursor compartilhado deixa de ocultar mensagens pendentes +de `receive()`, `receiveOne()`, `peek()`, `pendingCount()` e `hasPending()`. +Os recebimentos mantêm a ordem de sequência e seu limite de lote. Após a +atualização, um loop de recebimento pode retornar primeiro mensagens pendentes +antigas que o cursor compartilhado ocultava e depois as mais recentes. + +Um recebimento em replay retorna o que sua etapa original consumiu. Se a +chamada original não encontrou nada, o replay volta a não retornar nada. Um +handler de atualização executado pela primeira vez continua podendo receber. +Um fluxo mantido em uma propriedade agora registra os recebimentos na etapa +atual do workflow, em vez da etapa em que o fluxo foi aberto. Recebimentos que +versões anteriores registraram na etapa de abertura continuam sendo +reproduzidos em replay. + +Antes de reverter uma aplicação embutida para uma versão anterior à 2.20.3, +siga o [critério de replay](../testing.md#replay-before-deployment) com +históricos gravados pelo pacote mais recente. Versões anteriores procuram os +recebimentos de fluxos mantidos na etapa de abertura e podem fazer o replay +dessas execuções de outra forma. A reversão também restaura os erros do +cursor compartilhado, do replay de recebimentos vazios e da precisão do +processamento de tarefas fake. Veja as +[notas de compatibilidade da tag](https://github.com/durable-workflow/workflow/blob/2.20.3/CHANGELOG.md#2203---2026-11-04). + +A limitação de consultas em +[workflow#1024](https://github.com/durable-workflow/workflow/issues/1024) +permanece: uma consulta pode não retornar uma mensagem recebida por um handler +de atualização porque faz o replay do handler na etapa errada. A consulta não +altera linhas de mensagens. O replay do próprio workflow e a saída da execução +concluída continuam retornando o que o handler recebeu. + ## Recebimento de mensagens {#receiving-messages} Use `peek()` quando um workflow precisar inspecionar mensagens de entrada diff --git a/i18n/pt-BR/docusaurus-plugin-content-docs/current/testing.md b/i18n/pt-BR/docusaurus-plugin-content-docs/current/testing.md index e31e6e87970..d24a86dd133 100644 --- a/i18n/pt-BR/docusaurus-plugin-content-docs/current/testing.md +++ b/i18n/pt-BR/docusaurus-plugin-content-docs/current/testing.md @@ -174,6 +174,15 @@ public function testTimerWorkflow(): void `WorkflowStub::runReadyTasks()` processa apenas tarefas cujo prazo já chegou. Ele não avança o relógio do sistema nem força temporizadores futuros a disparar antes da hora. +O Workflow 2.20.3 processa tarefas fake no instante exato em que vencem, +incluindo frações de segundo, com a precisão de timestamps persistida pelo +modelo de tarefas configurado. Versões anteriores podiam ignorar tarefas do +SQLite que venciam naquele instante. Um prazo futuro com frações de segundo +permanece pendente até vencer. Atrasos de temporizador e backoff de novas +tentativas continuam usando segundos inteiros. Veja os +[limites de atualização e reversão de fluxos](./features/message-streams.md#stream-upgrades) +antes de reverter uma aplicação embutida para um pacote anterior. + ### Enviando sinais no modo fake {#sending-signals-in-fake-mode} Workflows que aguardam sinais podem recebê-los no modo fake. Quando você chama `$workflow->signal(...)`, o mecanismo registra o comando durável de sinal e cria uma tarefa de workflow. No modo fake, essa tarefa executa imediatamente no mesmo processo, então o workflow retoma de forma síncrona: diff --git a/i18n/pt-BR/source-hashes.json b/i18n/pt-BR/source-hashes.json index c8810e96662..d93da79ef10 100644 --- a/i18n/pt-BR/source-hashes.json +++ b/i18n/pt-BR/source-hashes.json @@ -41,7 +41,7 @@ "features/heartbeats.md": "e3d84178788dff92954e08d08f006def0a991a481f99301facbda8c6ca21a7a0", "features/local-activities.md": "05fca8f2104d8f4e7bd8b48040f5615f18d0ee2795922fb65c56f8d3d70ed204", "features/memo.md": "621aa630e37fbef6f84d761c92f99dc3fe8756879008c659cbad0600eb14fd5d", - "features/message-streams.md": "b30c7629d3fb9d20f27c4bcf0551457d65ac44a541b119312a2cde31aba48354", + "features/message-streams.md": "8a21b2e6dff51c69a3395d50ea6167e418ed793b4b7107b964f2a0f5f03a3801", "features/queries.md": "c66dd9542a062edd8158a46cebc9f1bf926aaf3599dca4a3122bd9860df6e2a2", "features/sagas.md": "8dae955491a54bcbf545ce6972928df59f3885e00f98bf3a57b14dad98f89161", "features/schedules.md": "717b9115ca62a69a3a1ea65f1bec68a0aebe0d5e6d2421df297bb129c597a523", @@ -104,6 +104,6 @@ "sdk-neutrality.md": "7b0714c123ade4904591870fc20e9a797da1e5485b2a6c87ca3eaa00c5de6ed6", "sponsors.md": "e85e14375743ca8fa50e3a48f894b160e28272573aa88480064f74010ebee98a", "support.md": "706807b3902599dda6080f632ec1f893017ea18bbe9585f533dcdbd6d85f4621", - "testing.md": "b80db83e74647e9559c1f0db442dcfe7c0e636d8c9842583c69f9ae46d68633d", + "testing.md": "250bc7dfd46f99eaeb392b329947813b064bda72026645198e3aefc80043a813", "waterline-operator-api.md": "2aca03b2c14100060b40be0bb033a82525ba924908834e9060ec746ead26f36d" } diff --git a/i18n/uk/docusaurus-plugin-content-docs/current/features/message-streams.md b/i18n/uk/docusaurus-plugin-content-docs/current/features/message-streams.md index f3ab245b7a3..3d3509474e9 100644 --- a/i18n/uk/docusaurus-plugin-content-docs/current/features/message-streams.md +++ b/i18n/uk/docusaurus-plugin-content-docs/current/features/message-streams.md @@ -38,7 +38,7 @@ continue-as-new до сервісного режиму. workflow застосунку. Фасад є стабільним контрактом. Сервіси повідомлень нижчого рівня призначені для інтеграції пакета та runtime. -:::warning Потоки повідомлень у Workflow 2.20.0 і раніших версіях +:::warning Потоки повідомлень до Workflow 2.20.3 Код workflow відтворюється під час кожного наступного завдання workflow і кожного query. У релізах Workflow до 2.20.0 включно `outbox()->sendReference()` записує @@ -46,23 +46,55 @@ query. У релізах Workflow до 2.20.0 включно `outbox()->sendRefe `inbox()->receive()` та `receiveOne()` під час відтворення можуть повернути інше повідомлення або жодного ([workflow#1010](https://github.com/durable-workflow/workflow/issues/1010)). -Workflow 2.20.1 виправляє це: відтворення повертає те, що надіслав або отримав -початковий виклик, а query ніколи не записує й не споживає повідомлення. +Workflow 2.20.1 записує надсилання й отримання для відтворення та не дозволяє +query записувати чи споживати повідомлення. Порожні отримання й потоки, збережені +між кроками, потребують додаткових виправлень відтворення у 2.20.3, описаних нижче. - Рядки, які продублювали попередні релізи, не видаляються. Задайте кожному логічному надсиланню сталий `idempotencyKey`, наприклад `reply:{turn}`, і усувайте дублікати за `idempotency_key` під час споживання потоку, який записав попередній реліз. Повідомлення, які попередній реліз спожив не на тому кроці, залишаються спожитими. -- У кожному релізі signals і всі потоки використовують один спільний курсор - повідомлень, тому signal, доставлений після повідомлення потоку, що чекає на - обробку, приховує це повідомлення +- Signals, updates і всі потоки використовують один спільний курсор + повідомлень. До 2.20.2 включно signal, update або отримання з іншого потоку + можуть пересунути його за повідомлення, що чекають на обробку, і приховати їх ([workflow#1011](https://github.com/durable-workflow/workflow/issues/1011)). - Отримуйте повідомлення лише після того, як signal або умова вказує, що - повідомлення є, і надсилайте цей signal перед повідомленням. + Для цього випадку з порядком signal у тих версіях надсилайте signal перед + повідомленням і отримуйте лише після того, як signal або умова вказує, що + повідомлення є. ::: +## Оновлення потоків і відкочування {#stream-upgrades} + +У Workflow 2.20.3 спільний курсор більше не приховує повідомлення, що чекають +на обробку, від `receive()`, `receiveOne()`, `peek()`, `pendingCount()` або +`hasPending()`. Отримання зберігають порядок номерів і обмеження розміру пакета. +Після оновлення цикл отримання може спершу повернути старіші повідомлення, які +раніше приховував спільний курсор, а вже потім новіші. + +Відтворене отримання повертає те, що спожив початковий крок. Якщо початковий +виклик нічого не знайшов, відтворення знову нічого не повертає. Обробник update, +що виконується вперше, і далі може отримувати повідомлення. Потік, збережений +у властивості, тепер записує отримання на поточному кроці workflow, а не на +кроці відкриття потоку. Отримання, які попередні релізи записали на кроці +відкриття, і далі відтворюються. + +Перед відкочуванням вбудованого застосунку до версії нижче 2.20.3 виконайте +[перевірку відтворення](../testing.md#replay-before-deployment) на історіях, +записаних новішим пакетом. Попередні версії шукають отримання збереженого потоку +на кроці відкриття та можуть інакше відтворювати такі запуски. Відкочування +також повертає помилки спільного курсора, відтворення порожніх отримань і +точності виконання завдань fake. Див. +[примітки щодо сумісності для тегу](https://github.com/durable-workflow/workflow/blob/2.20.3/CHANGELOG.md#2203---2026-11-04). + +Обмеження query у +[workflow#1024](https://github.com/durable-workflow/workflow/issues/1024) +залишається: query може нічого не повернути для повідомлення, яке отримав +обробник update, бо відтворює обробник не на тому кроці. Query не змінює рядків +повідомлень. Власне відтворення workflow та результат завершеного запуску й +далі повертають те, що отримав обробник. + ## Отримання повідомлень {#receiving-messages} Використовуйте `peek()`, коли workflow має перевірити вхідні повідомлення, diff --git a/i18n/uk/docusaurus-plugin-content-docs/current/testing.md b/i18n/uk/docusaurus-plugin-content-docs/current/testing.md index c1c8ff20613..37f69aa7e5c 100644 --- a/i18n/uk/docusaurus-plugin-content-docs/current/testing.md +++ b/i18n/uk/docusaurus-plugin-content-docs/current/testing.md @@ -183,6 +183,15 @@ public function testTimerWorkflow(): void `WorkflowStub::runReadyTasks()` виконує лише завдання, час яких уже настав. Він не переміщує реальний час і не змушує майбутні timer спрацьовувати раніше. +Workflow 2.20.3 виконує завдання fake точно в момент їхньої готовності, +включно з дробовими частками секунди, з точністю часових позначок, яку зберігає +налаштована модель завдань. Попередні версії могли пропускати завдання SQLite, +час виконання яких щойно настав. Завдання з майбутнім строком із дробовою +часткою секунди залишається в очікуванні до настання цього строку. Затримки +timer і backoff повторних спроб і далі задаються цілими секундами. Перед +відкочуванням вбудованого застосунку до старішого пакета перегляньте +[обмеження оновлення потоків і відкочування](./features/message-streams.md#stream-upgrades). + ### Надсилання signal у режимі fake {#sending-signals-in-fake-mode} Workflow, що очікують signal, можуть отримувати їх у fake. Виклик diff --git a/i18n/uk/source-hashes.json b/i18n/uk/source-hashes.json index c8810e96662..d93da79ef10 100644 --- a/i18n/uk/source-hashes.json +++ b/i18n/uk/source-hashes.json @@ -41,7 +41,7 @@ "features/heartbeats.md": "e3d84178788dff92954e08d08f006def0a991a481f99301facbda8c6ca21a7a0", "features/local-activities.md": "05fca8f2104d8f4e7bd8b48040f5615f18d0ee2795922fb65c56f8d3d70ed204", "features/memo.md": "621aa630e37fbef6f84d761c92f99dc3fe8756879008c659cbad0600eb14fd5d", - "features/message-streams.md": "b30c7629d3fb9d20f27c4bcf0551457d65ac44a541b119312a2cde31aba48354", + "features/message-streams.md": "8a21b2e6dff51c69a3395d50ea6167e418ed793b4b7107b964f2a0f5f03a3801", "features/queries.md": "c66dd9542a062edd8158a46cebc9f1bf926aaf3599dca4a3122bd9860df6e2a2", "features/sagas.md": "8dae955491a54bcbf545ce6972928df59f3885e00f98bf3a57b14dad98f89161", "features/schedules.md": "717b9115ca62a69a3a1ea65f1bec68a0aebe0d5e6d2421df297bb129c597a523", @@ -104,6 +104,6 @@ "sdk-neutrality.md": "7b0714c123ade4904591870fc20e9a797da1e5485b2a6c87ca3eaa00c5de6ed6", "sponsors.md": "e85e14375743ca8fa50e3a48f894b160e28272573aa88480064f74010ebee98a", "support.md": "706807b3902599dda6080f632ec1f893017ea18bbe9585f533dcdbd6d85f4621", - "testing.md": "b80db83e74647e9559c1f0db442dcfe7c0e636d8c9842583c69f9ae46d68633d", + "testing.md": "250bc7dfd46f99eaeb392b329947813b064bda72026645198e3aefc80043a813", "waterline-operator-api.md": "2aca03b2c14100060b40be0bb033a82525ba924908834e9060ec746ead26f36d" } diff --git a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/features/message-streams.md b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/features/message-streams.md index df6f0b6afcf..705a3080b52 100644 --- a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/features/message-streams.md +++ b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/features/message-streams.md @@ -28,15 +28,43 @@ keywords: 不要从应用工作流代码直接写入 `workflow_messages` 行或游标行。门面才是稳定契约;底层消息服务用于包/运行时集成。 -:::warning Workflow 2.20.0 及更早版本中的消息流 +:::warning Workflow 2.20.3 之前的消息流 -工作流代码会在之后的每个工作流任务和每次查询时重放。在 Workflow 2.20.0 及更早的版本中,`outbox()->sendReference()` 每次重放都会写入新的出站消息和入站消息,而 `inbox()->receive()` 和 `receiveOne()` 在重放时可能返回不同的消息或不返回消息([workflow#1010](https://github.com/durable-workflow/workflow/issues/1010))。Workflow 2.20.1 修复了此问题:重放会返回原始调用所发送或接收的内容,查询永远不会写入或消费消息。 +工作流代码会在之后的每个工作流任务和每次查询时重放。在 Workflow 2.20.0 及更早的版本中,`outbox()->sendReference()` 每次重放都会写入新的出站消息和入站消息,而 `inbox()->receive()` 和 `receiveOne()` 在重放时可能返回不同的消息或不返回消息([workflow#1010](https://github.com/durable-workflow/workflow/issues/1010))。Workflow 2.20.1 会记录发送和接收以供重放,并阻止查询写入或消费消息。 +空接收和跨步骤保留的流还需要下文介绍的 2.20.3 重放修复。 - 早期版本重复写入的行不会被删除。请为每次逻辑发送提供稳定的 `idempotencyKey`,例如 `reply:{turn}`,并在消费由早期版本写入的流时按 `idempotency_key` 去重。早期版本在错误步骤下消费的消息仍保持已消费状态。 -- 在所有版本中,信号和所有流共享同一个消息游标,因此在待处理流消息之后送达的信号会隐藏该消息([workflow#1011](https://github.com/durable-workflow/workflow/issues/1011))。只有在信号或条件表明有消息到达后才接收,并在发送消息之前发送该信号。 +- 信号、更新和所有流共享同一个消息游标。在 2.20.2 及更早版本中,信号、 + 更新或另一条流上的接收可能将游标移到待处理消息之后,从而隐藏这些消息 + ([workflow#1011](https://github.com/durable-workflow/workflow/issues/1011))。 + 对于这些版本中的信号顺序问题,请在消息之前发送信号,并且只在信号或条件 + 表明有消息时才接收。 ::: +## 流升级与回退 {#stream-upgrades} + +在 Workflow 2.20.3 中,共享游标不再对 `receive()`、`receiveOne()`、`peek()`、 +`pendingCount()` 或 `hasPending()` 隐藏待处理消息。接收仍遵守序号顺序和 +批次大小限制。升级后,接收循环可能先返回以前被共享游标隐藏的较早待处理 +消息,再返回较新的消息。 + +重放的接收返回原始步骤消费的内容。如果原始调用没有找到消息,重放时仍然 +不返回消息。首次执行的更新处理器仍可以接收消息。保存在属性中的流现在按 +当前工作流步骤记录接收,而不是按打开流时的步骤记录。旧版本按打开步骤 +记录的接收仍可重放。 + +在将嵌入式应用回退到 2.20.3 之前的版本前,请使用新包写入的历史通过 +[重放测试门槛](../testing.md#replay-before-deployment)。旧版本按打开步骤 +查找保留流的接收,可能以不同方式重放这些运行。回退还会恢复共享游标、 +空接收重放和 fake 任务处理精度问题。参阅 +[该标签的兼容性说明](https://github.com/durable-workflow/workflow/blob/2.20.3/CHANGELOG.md#2203---2026-11-04)。 + +[workflow#1024](https://github.com/durable-workflow/workflow/issues/1024) +中的查询限制仍然存在:查询可能不返回更新处理器已接收的消息,因为它在 +错误的步骤重放处理器。查询不会更改消息行。工作流自身的重放和完成后的 +输出仍会返回处理器接收的内容。 + ## 接收消息 {#receiving-messages} 工作流只需检查待处理入站消息,不推进持久游标时,使用 `peek()`。准备消费消息并在历史中记录游标推进时,使用 `receive()` 或 `receiveOne()`。 diff --git a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/testing.md b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/testing.md index a54548c6818..c76fe2bd204 100644 --- a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/testing.md +++ b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/testing.md @@ -170,6 +170,12 @@ public function testTimerWorkflow(): void `WorkflowStub::runReadyTasks()` 仅排空已经到期的任务。它不会快进实际时钟,也不会强制尚未到期的延迟定时器提前触发。 +Workflow 2.20.3 按配置的任务模型所持久化的时间戳精度,在准确的到期 +时刻处理 fake 任务,包括小数秒。旧版本可能跳过恰在该时刻到期的 SQLite +任务。带小数秒的未来期限会保持待处理状态,直到真正到期。定时器延迟和 +重试退避仍使用整秒。在将嵌入式应用回退到旧包之前,请参阅 +[流升级与回退限制](./features/message-streams.md#stream-upgrades)。 + ### 在 fake 模式下发送信号 {#sending-signals-in-fake-mode} 等待信号的工作流可以在 fake 模式下接收信号。调用 `$workflow->signal(...)` 时,引擎记录持久信号命令并创建工作流任务。Fake 模式下该任务内联执行,因此工作流同步恢复: diff --git a/i18n/zh-Hans/source-hashes.json b/i18n/zh-Hans/source-hashes.json index c8810e96662..d93da79ef10 100644 --- a/i18n/zh-Hans/source-hashes.json +++ b/i18n/zh-Hans/source-hashes.json @@ -41,7 +41,7 @@ "features/heartbeats.md": "e3d84178788dff92954e08d08f006def0a991a481f99301facbda8c6ca21a7a0", "features/local-activities.md": "05fca8f2104d8f4e7bd8b48040f5615f18d0ee2795922fb65c56f8d3d70ed204", "features/memo.md": "621aa630e37fbef6f84d761c92f99dc3fe8756879008c659cbad0600eb14fd5d", - "features/message-streams.md": "b30c7629d3fb9d20f27c4bcf0551457d65ac44a541b119312a2cde31aba48354", + "features/message-streams.md": "8a21b2e6dff51c69a3395d50ea6167e418ed793b4b7107b964f2a0f5f03a3801", "features/queries.md": "c66dd9542a062edd8158a46cebc9f1bf926aaf3599dca4a3122bd9860df6e2a2", "features/sagas.md": "8dae955491a54bcbf545ce6972928df59f3885e00f98bf3a57b14dad98f89161", "features/schedules.md": "717b9115ca62a69a3a1ea65f1bec68a0aebe0d5e6d2421df297bb129c597a523", @@ -104,6 +104,6 @@ "sdk-neutrality.md": "7b0714c123ade4904591870fc20e9a797da1e5485b2a6c87ca3eaa00c5de6ed6", "sponsors.md": "e85e14375743ca8fa50e3a48f894b160e28272573aa88480064f74010ebee98a", "support.md": "706807b3902599dda6080f632ec1f893017ea18bbe9585f533dcdbd6d85f4621", - "testing.md": "b80db83e74647e9559c1f0db442dcfe7c0e636d8c9842583c69f9ae46d68633d", + "testing.md": "250bc7dfd46f99eaeb392b329947813b064bda72026645198e3aefc80043a813", "waterline-operator-api.md": "2aca03b2c14100060b40be0bb033a82525ba924908834e9060ec746ead26f36d" } diff --git a/static/stable-releases.json b/static/stable-releases.json index 502d9999eaa..9f2bed863cd 100644 --- a/static/stable-releases.json +++ b/static/stable-releases.json @@ -10,7 +10,7 @@ "sdk-rust": "4.11.2", "server": "3.0.5", "waterline": "2.14.0", - "workflow": "2.20.2" + "workflow": "2.20.3" }, "helm_chart": { "app_version": "3.0.5",