diff --git a/docs/compatibility.md b/docs/compatibility.md index 33b82a3a38e..8267d3ac0c6 100644 --- a/docs/compatibility.md +++ b/docs/compatibility.md @@ -99,12 +99,12 @@ The embedded package and the service-mode SDK have separate support contracts. | Package line | PHP | Laravel | | --- | --- | --- | -| Current embedded Workflow 2.24 | PHP 8.2+ in 8.x; PHP 8.3+ for Laravel 13 | `^12.69.0` or `^13.30.0` | +| Current embedded Workflow 2.26 | PHP 8.2+ in 8.x; PHP 8.3+ for Laravel 13 | `^12.69.0` or `^13.30.0` | | Embedded Workflow 2.20.5 | PHP `^8.1`, subject to Laravel's own minimum | `^10.50.4`, `^11.56.1`, `^12.69.0` or `^13.30.0` | | Published PHP SDK 3.14 | Bare SDK PHP `^8.1`; the Laravel bridge needs PHP `^8.2`, and PHP 8.3+ for Laravel 13 | `^12.69.0` or `^13.30.0` | | PHP SDK 3.9.5 | Bare SDK PHP `^8.1`; the Laravel bridge also follows Laravel's PHP minimum | `^10.50.4`, `^11.56.1`, `^12.69.0` or `^13.30.0` | -The [published embedded upgrade contract](https://github.com/durable-workflow/workflow/blob/2.24.0/resources/laravel-embedded-upgrade-contract.json) +The [published embedded upgrade contract](https://github.com/durable-workflow/workflow/blob/2.26.0/resources/laravel-embedded-upgrade-contract.json) and each release's `composer.json` are the package authorities. The current embedded release was verified on Laravel 12 with PHP 8.2–8.4 and Laravel 13 with PHP 8.3–8.4. Its PHP 8.1 and Laravel 10/11 support has been removed. This does @@ -161,6 +161,38 @@ See the release notes for [2.23.2](https://github.com/durable-workflow/workflow/releases/tag/2.23.2) and [2.24.0](https://github.com/durable-workflow/workflow/releases/tag/2.24.0). +Workflow 2.25 and 2.26 keep the 2.21 support floors and the embedded worker +protocol `1.22`. 2.25 adds no database migration. 2.26 adds one, so run +`php artisan migrate` when you upgrade. It creates the +`workflow_child_supervisions` table. Changes to check before upgrading: + +- From 2.26, a parent that continues as new while children it started are + still open hands them to the continued run. The chain's final run applies + their parent-close policy, and a child that fails is still retried under its + recorded retry policy. See + [Continue-as-new and open children](./features/child-workflows.md#continue-as-new-and-open-children). +- From 2.26, the migrations from earlier releases that fill in existing rows + (`2026_07_13`, `2026_09_24`, `2026_09_29` and `2026_10_11`) no longer lock the + table for the whole backfill. They add the column first, fill rows in small + batches and then build their indexes without blocking writes. If one of them + is interrupted, run `php artisan migrate` again. Installs that already ran + them are not affected. +- From 2.26, redrive reuses a child workflow that completed before the failure. + Releases before 2.26 replay such a successor with a different workflow time + after the reused child, so keep workers on 2.26 or later once one exists. See + [Redrive a Failed Run](./failures-and-recovery.md#redrive). +- From 2.26, `historyBudgetAtStep()` and `shouldContinueAsNewAtStep()` read + the history budget the same way on every replay. Use them in loops. See + [History Budget](./features/continue-as-new.md#history-budget). +- From 2.25, going over a fixed memo or search attribute cap raises + `StructuralLimitExceededException` instead of `InvalidArgumentException`, + and the `memo_size_bytes` default is 65,536. See + [Structural Limits](./constraints/structural-limits.md). + +See the release notes for +[2.25.0](https://github.com/durable-workflow/workflow/releases/tag/2.25.0) and +[2.26.0](https://github.com/durable-workflow/workflow/releases/tag/2.26.0). + ## Stability Levels Every public surface in Durable Workflow carries exactly one of these diff --git a/docs/defining-workflows/workflow-api.md b/docs/defining-workflows/workflow-api.md index 00d27ac700a..ac599cffd72 100644 --- a/docs/defining-workflows/workflow-api.md +++ b/docs/defining-workflows/workflow-api.md @@ -55,6 +55,8 @@ abstract class Workflow public function historyLength(): int; public function historySize(): int; public function shouldContinueAsNew(): bool; + public function historyBudgetAtStep(): array; + public function shouldContinueAsNewAtStep(): bool; } ``` @@ -67,6 +69,8 @@ abstract class Workflow | `historyLength()` | The workflow needs a count-based history budget signal. | Current history event count. | | `historySize()` | The workflow needs a byte-based history budget signal. | Approximate persisted history size in bytes. | | `shouldContinueAsNew()` | The workflow should rotate before history becomes expensive. | `true` when configured history budgets recommend rotation. | +| `historyBudgetAtStep()` | The workflow reads the budget more than once in a run, for example in a loop (Workflow 2.26+). | Budget counters as of the current step, the same on every replay. | +| `shouldContinueAsNewAtStep()` | A loop decides whether to rotate (Workflow 2.26+). | `true` when the history before the current step crosses a configured budget. | ## Durable commands diff --git a/docs/failures-and-recovery.md b/docs/failures-and-recovery.md index 119773a7183..033394855e0 100644 --- a/docs/failures-and-recovery.md +++ b/docs/failures-and-recovery.md @@ -117,6 +117,7 @@ The successor replays workflow code from the start: - A memo or search attribute that workflow code upserted before the failed step is reused in step order, and the successor keeps the same values. - A signal wait (`await('name')`) that received and applied its signal is reused with the signal's value. The signal is not delivered again. - An update that was accepted, applied and completed before the failed step is recorded again at the same position. Replay runs the update handler from its recorded arguments, so the workflow's state matches. The update is not delivered again. A rejected update, and one the failure closed before it ran, are left out. +- In Workflow 2.26 and later, a child workflow call that completed before the failed step returns its recorded result. The child is not started again. The successor records the call's `ChildWorkflowScheduled`, `ChildRunStarted` and `ChildRunCompleted` events and keeps the original child instance, child run, link id and call id, but gets no child link of its own. - `outbox()->sendReference()` and `inbox()->receive()` in reused workflow code return the message the failed run sent or consumed. They don't send or consume it again. A replayed receive whose original call found nothing reads the stream again. - In Workflow 2.20.2 and later, inbound stream messages still pending on the failed run move to the successor. Workflow 2.20.1 and earlier left them on the failed run, so the successor never received them ([workflow#1013](https://github.com/durable-workflow/workflow/issues/1013)). - If an activity failure ended the run, the failed activity call is scheduled as a new activity execution, using the retry policy in the workflow code. Its attempts start again. @@ -126,7 +127,7 @@ The successor replays workflow code from the start: - The successor keeps the failed run's execution deadline. Its run timeout starts again at the redrive. - Each reused step carries `reused_from_run_id` and `reused_recorded_at`. On a reused update or signal event, the two always come as a pair. - A successor that reused steps can be redriven again. A reused signal or update payload keeps the run that first recorded it in `workflow_run_id`, `reused_from_run_id` names the run it was redriven from, and every reused step keeps the time it first ran, so a chain of redrives reuses each step once. -- In embedded mode, `Workflow::now()` in the successor starts at the failed run's start time. Replay uses `reused_recorded_at`, so `Workflow::now()` after a reused step equals the time in the failed run. A step reused by a second redrive keeps the time it first ran. +- In embedded mode, `Workflow::now()` in the successor starts at the failed run's start time. Replay uses `reused_recorded_at`, so `Workflow::now()` after a reused step equals the time in the failed run. After a reused child workflow call, that is the time the child first finished. A step reused by a second redrive keeps the time it first ran. ### Request a redrive {#request-a-redrive} @@ -182,11 +183,12 @@ Redrive accepts a failed run when all of these are true: - The run is the instance's current run. - The run failed because an activity failure reached workflow code and was not caught, or because workflow code threw or a structural limit stopped it. A run that failed on a workflow timeout is refused. -- Every step before the failed step is a completed activity, a side effect, a version marker, a `timer()` that fired, a memo or search-attribute upsert, a signal wait that received and applied its signal, or an update that was accepted, applied and completed with the same arguments. A rejected update, and one the failure closed before it ran, are allowed and left out. Activity, side effect, signal and update payloads must be stored inline. A payload held in external payload storage is refused. +- Every step before the failed step is a completed activity, a side effect, a version marker, a `timer()` that fired, a memo or search-attribute upsert, a signal wait that received and applied its signal, an update that was accepted, applied and completed with the same arguments, or, in Workflow 2.26 and later, a child workflow call that completed. A rejected update, and one the failure closed before it ran, are allowed and left out. Activity, side effect, signal, update and child result payloads must be stored inline. A payload held in external payload storage is refused. - The workflow definition matches the fingerprint recorded when the run started, or you passed `allow_definition_change` and the corrected code replays the completed steps. A workflow-code failure on the same definition is refused. - The execution deadline has not passed. -- The run has no parent workflow, no child workflows and no local activities, and its input is stored inline. -- If a service worker started the run, the steps before the failure are only activities, side effects, version markers and fired timers. Memo and search-attribute upserts, signal waits and applied updates are refused for service runs. +- The run has no parent workflow and no local activities, and its input is stored inline. Before Workflow 2.26, it also has no child workflows. A run that is itself a child is never redriven, because its parent has already recorded the child's outcome. +- Each child workflow call before the failed step completed on its own, outside a parallel group or cancellation scope, without a retry or continue-as-new. +- If a service worker started the run, the steps before the failure are only activities, side effects, version markers and fired timers. Memo and search-attribute upserts, signal waits, applied updates and completed child workflow calls are refused for service runs. A refusal names the first rule that failed: @@ -196,7 +198,12 @@ A refusal names the first rule that failed: | `source_run_not_current` | A newer run of the instance exists. | | `unrecorded_failure_boundary` | The run's failure has no recorded step, such as a workflow-code failure recorded by a release before 2.19.0. | | `workflow_code_failure_requires_corrected_definition` | Workflow code threw, and the definition hasn't changed, so the same code would throw again. | -| `unsupported_history` | The history before the failure contains a step that redrive cannot reuse, such as a child workflow or a cancelled timer. | +| `unsupported_history` | The history before the failure contains a step that redrive cannot reuse, such as a cancelled timer. Before Workflow 2.26, any child workflow. | +| `unsupported_open_child` | A child workflow call before the failure never closed. Workflow 2.26 and later. | +| `unsupported_child_outcome` | A child workflow before the failure failed, was cancelled or was terminated. Workflow 2.26 and later. | +| `unsupported_child_workflow` | A child workflow call is in a parallel group or cancellation scope, was retried or continued as new, or its events don't name one child call. Workflow 2.26 and later. | +| `external_child_result_not_supported` | A completed child workflow's result is stored in external payload storage. Workflow 2.26 and later. | +| `unavailable_child_result` | A completed child workflow's result cannot be decoded. Workflow 2.26 and later. | | `unsupported_local_activity` | The history contains a local activity. | | `unsupported_timer` | The history contains a condition or signal timeout, a cancellation cleanup timer, or a timer inside a cancellation scope or parallel group. | | `incomplete_timer_step` | A timer step does not have both its scheduled and fired events. | @@ -223,7 +230,7 @@ A refusal names the first rule that failed: | `definition_incompatible_with_prefix` | The corrected code can't replay the completed steps. `definition_mismatch` names the first step that differs. | | `definition_check_over_budget` | The completed history is larger than the history budget the replay check allows. | | `definition_change_requires_replay_check` | A service worker started the run, so redrive can't check a changed definition. | -| `service_redrive_history_not_qualified` | A service worker started the run, and the steps before the failure include a memo upsert, search-attribute upsert, signal wait or applied update. Redrive refuses these steps for service runs until it can check each SDK runtime's replay capability for them. | +| `service_redrive_history_not_qualified` | A service worker started the run, and the steps before the failure include a memo upsert, search-attribute upsert, signal wait, applied update or completed child workflow call. Redrive refuses these steps for service runs until it can check each SDK runtime's replay capability for them. | | `request_id_already_used` | The `request_id` was already used for another redrive of the instance. | | `already_redriven` | Reported by run detail and `describe()` for a run that was already redriven. A redrive request for it returns the existing successor instead. | | `invalid_request_id` | The `request_id` is longer than 191 characters. | @@ -245,6 +252,8 @@ In Workflow 2.20.0 and later, run detail and `describe()` report the redrive lin ### Earlier releases and the native Server {#redrive-earlier-releases} +Workflow releases before 2.26.0 refuse any child workflow in the history with `unsupported_history`. They ignore `reused_recorded_at` on child workflow events, so a 2.26.0 successor that reused a child call can replay there with a different workflow time, and different deadlines, after the call. They also refuse to redrive it again. Once such a successor exists, keep workers on 2.26.0 or later, or confirm that no such history can replay, before you roll back. + Workflow 2.20.0 refuses nothing that 2.20.1 accepts. In 2.20.0, `outbox()->sendReference()` in reused workflow code sends again, and a replayed `inbox()->receive()` can return different messages or none, or consume a newer message ([workflow#1010](https://github.com/durable-workflow/workflow/issues/1010)). Workflow 2.19.0 refuses an applied update (`unsupported_history`). It also refuses to redrive a successor that reused an update (`unsupported_history`) or a signal wait (`mismatched_signal_receipt`). Run detail and `describe()` show redrive links as diagnostic fallbacks. diff --git a/docs/features/child-workflows.md b/docs/features/child-workflows.md index 47c8424d8b6..c4727627aac 100644 --- a/docs/features/child-workflows.md +++ b/docs/features/child-workflows.md @@ -203,7 +203,7 @@ $results = all([ - When the parent run closes for any reason, the engine queries open child links with a non-abandon policy and sends the appropriate command (request cancellation, cancel, or terminate) to each open child. - If the child has already closed by the time the policy is enforced, no action is taken — the command is silently skipped. - Policy enforcement is best-effort: if a child command is rejected (e.g. the child is already terminal), the parent's closure is not affected. When enforcement succeeds, a `ParentClosePolicyApplied` history event is recorded on the parent run. When enforcement fails, a `ParentClosePolicyFailed` history event is recorded instead, so operators can distinguish successful enforcement from silent failures. -- Continue-as-new does **not** trigger parent-close policy, because the workflow instance remains active under a new run. +- Continue-as-new does **not** trigger parent-close policy, because the workflow instance remains active under a new run. From Workflow 2.26, the chain's final run applies it instead. See [Continue-as-new and open children](#continue-as-new-and-open-children). ### Parent disposition matrix @@ -216,9 +216,21 @@ Parent-close policy fires on every terminal parent disposition, and stays inert | Timed out | Yes | Fires after `WorkflowTimedOut` is recorded for run-timeout and execution-timeout closures. | | Cancelled | Yes | Fires after the accepted `CancelRequested` command closes the parent run. | | Terminated | Yes | Fires after the accepted `TerminateRequested` command closes the parent run. | -| Continue-as-new | No | The workflow instance stays active under the new run, so existing child links are re-pointed at the continued run with their original policy preserved. | +| Continue-as-new | No | The workflow instance stays active under the new run. From Workflow 2.26, the continued run takes over supervising the open children, and the chain's final run applies their policy. | | Reset | Not currently applicable | The v2 runtime does not expose a standalone reset command or reset terminal disposition. A future reset or repair operation that closes or replaces a parent run must define whether child ownership transfers; if the old run becomes terminal, it must apply parent-close policy before it stops owning open children. | +### Continue-as-new and open children {#continue-as-new-and-open-children} + +In Workflow 2.26 and later, a parent that continues as new while children it started are still open hands them to the continued run, in the same transaction. Embedded and service-mode runs behave the same: + +- Each open child gets a row in the `workflow_child_supervisions` table, which the 2.26 migration creates. A child that has already closed is not handed on. +- The child link, child call, sequence, deadlines and parent-close policy stay as the starting run recorded them. When the continued run continues as new again, it hands the children on again. +- When the chain's final run completes, fails, times out, is cancelled or is terminated, it applies each child's policy and records `ParentClosePolicyApplied` or `ParentClosePolicyFailed` in its own history. `abandon` stays `abandon`. The closed earlier run gets no new history. +- The continued run has no handle on these children, and their results are not delivered to it. Pass anything the next run needs in the arguments to `continueAsNew()`. +- A handed-on child that fails is retried under the retry policy the starting run recorded, with the same child call identity and attempt count, while a run of the chain still supervises it. The retry run's `WorkflowStarted` names the starting run as its parent, and the chain's final run applies the parent-close policy to the retry run. The failure is final once the attempts are spent, the failure is non-retryable, or the chain has closed. + +Before 2.26, these children kept running after the chain closed and their policy was never applied, and a child that failed after its parent continued as new was not retried. See the [2.26.0 release notes](https://github.com/durable-workflow/workflow/releases/tag/2.26.0). + ### When to use each policy **Abandon** (default) is correct when children represent independent work that should complete regardless of the parent's fate — for example, a notification workflow or a cleanup task that must finish. diff --git a/docs/features/continue-as-new.md b/docs/features/continue-as-new.md index c8ba9d80cdb..a1847fdb2c9 100644 --- a/docs/features/continue-as-new.md +++ b/docs/features/continue-as-new.md @@ -77,10 +77,14 @@ explicitly on the predecessor. Long-lived loops can shed history without inventing a new public workflow id every time the run rolls forward. -## History Budget +## History Budget {#history-budget} Workflow code can observe its current history length and a continue-as-new suggestion flag through explicit runtime context. This lets long-lived loops hand off deliberately before they hit history-budget cliffs. +In Workflow 2.26 and later, use `shouldContinueAsNewAtStep()` and `historyBudgetAtStep()`. They count only the history recorded before the current workflow step, so the same line returns the same answer on every replay. A loop that checks the budget on each iteration continues as new once, at the first iteration that crosses the threshold. + +The older methods read the whole current history. Inside a loop, an earlier iteration can see a later total on replay and take a different branch than it took the first time. They are unchanged, so runs that already decided with them keep replaying. + ```php use function Workflow\V2\activity; use function Workflow\V2\continueAsNew; @@ -108,6 +112,8 @@ class PollingWorkflow extends Workflow | `$this->historyLength()` | `int` | Number of history events in the current run | | `$this->historySize()` | `int` | Total size of history events in bytes | | `$this->shouldContinueAsNew()` | `bool` | `true` when the run exceeds the configured event count or byte size budget | +| `$this->historyBudgetAtStep()` | `array` | The budget as of the current step: `history_event_count`, `history_size_bytes`, `history_fan_out`, `continue_as_new_recommended`, `pressure`, `pressure_dimensions` and `observation` (`step_prefix.v1`). Workflow 2.26 and later. | +| `$this->shouldContinueAsNewAtStep()` | `bool` | `continue_as_new_recommended` from `historyBudgetAtStep()`. Use it in loops. Workflow 2.26 and later. | ### Configuration @@ -123,7 +129,7 @@ The continue-as-new recommendation thresholds are configurable: ], ``` -`shouldContinueAsNew()` returns `true` when either threshold is crossed. Run summaries also track `history_event_count`, `history_size_bytes`, and `continue_as_new_recommended` so Waterline can flag long-lived runs in fleet views. +`shouldContinueAsNew()` and `shouldContinueAsNewAtStep()` return `true` when either threshold is crossed. Run summaries also track `history_event_count`, `history_size_bytes`, and `continue_as_new_recommended` so Waterline can flag long-lived runs in fleet views. ## Metadata Carry-Forward @@ -163,6 +169,8 @@ class PollingWorkflow extends Workflow } ``` +A parent that continues as new while child workflows it started are still open hands them to the continued run. See [Continue-as-new and open children](./child-workflows.md#continue-as-new-and-open-children). + For long-lived human-input or assistant loops, prefer the first-class `$this->inbox()` / `$this->outbox()` [Message Streams](./message-streams.md) facade. Pending stream messages and the cursor position move to the continued diff --git a/docs/features/search-attributes.md b/docs/features/search-attributes.md index 395664a552a..5c0db55bb4a 100644 --- a/docs/features/search-attributes.md +++ b/docs/features/search-attributes.md @@ -105,7 +105,7 @@ On the Server you can register a search attribute with a type through `POST /api Registration only constrains the keys you register. From native Server 3.5.0, a key that is not registered is still accepted and its type is inferred, as in a namespace with no registered attributes. Registering one attribute does not break running workflows that upsert other keys. PHP Server 2.x and native Server before 3.5.0 refuse every unregistered key once any attribute is registered, so register all the keys your workflows use before registering the first one there. -Deleting a registration stops checking that key. Stored values and running workflows are not changed, and later upserts of the key are inferred again. +Deleting a registration stops checking that key. Stored values and running workflows are not changed, and later upserts of the key are inferred again. On native Server, a list query that filters on a key that is not registered, including one whose registration you deleted, is refused because the key is not defined in the namespace. To change an attribute's type, register a new attribute name with the new type, update your workflows to write it, and filter on the new name once existing runs have caught up. Deleting and re-registering the same name with a different type leaves earlier values in the old type. diff --git a/docs/polyglot/php.md b/docs/polyglot/php.md index 4bee561219a..8e9909daaa2 100644 --- a/docs/polyglot/php.md +++ b/docs/polyglot/php.md @@ -326,7 +326,9 @@ New in these releases: the `Worker` constructor to submit the next workflow commands together with a successful activity result when the Server advertises `activity_workflow_continuation` (native Server 3.4.0 or later). It defaults - to `false`. Use 3.12.1 or later if you enable it, and drain or disable + to `false`. Turning it on currently costs throughput: in our benchmark under + load, workflows ran 24–49% slower with it on and used twice as many database + transactions ([measurement](https://github.com/durable-workflow/server/issues/1078)). Use 3.12.1 or later if you enable it, and drain or disable opted-in workers before downgrading the Server or adding older Server nodes. See the [3.14.0 changelog](https://github.com/durable-workflow/sdk-php/blob/3.14.0/CHANGELOG.md) diff --git a/docs/testing.md b/docs/testing.md index 790a4195b85..e385a432875 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -355,7 +355,7 @@ Both policies record durable command and history events, so you can also assert ### Testing History Budget -The `HistoryBudget` fields (`history_event_count`, `history_size_bytes`, `continue_as_new_recommended`) are surfaced on the run summary projection and are available through the `RunDetailView`. In your workflow code, the `Workflow` base class exposes these as `$this->historyLength()`, `$this->historySize()`, and `$this->shouldContinueAsNew()`: +The `HistoryBudget` fields (`history_event_count`, `history_size_bytes`, `continue_as_new_recommended`) are surfaced on the run summary projection and are available through the `RunDetailView`. In your workflow code, the `Workflow` base class exposes these as `$this->historyLength()`, `$this->historySize()`, and `$this->shouldContinueAsNew()`. Inside a loop, use `$this->shouldContinueAsNewAtStep()` (Workflow 2.26 and later), which gives the same answer on every replay: ```php use Workflow\V2\Workflow; @@ -367,7 +367,7 @@ final class LongRunningWorkflow extends Workflow while (true) { // ... process work ... - if ($this->shouldContinueAsNew()) { + if ($this->shouldContinueAsNewAtStep()) { Workflow::continueAsNew($this->carryForwardState()); } } diff --git a/i18n/de/docusaurus-plugin-content-docs/current/compatibility.md b/i18n/de/docusaurus-plugin-content-docs/current/compatibility.md index 22d0ad89692..edd8a1cc8a1 100644 --- a/i18n/de/docusaurus-plugin-content-docs/current/compatibility.md +++ b/i18n/de/docusaurus-plugin-content-docs/current/compatibility.md @@ -66,12 +66,12 @@ Das eingebettete Paket und das Service-Modus-SDK haben eigene Supportverträge. | Paketlinie | PHP | Laravel | | --- | --- | --- | -| Aktuelles eingebettetes Workflow 2.24 | PHP 8.2+ in 8.x; PHP 8.3+ für Laravel 13 | `^12.69.0` oder `^13.30.0` | +| Aktuelles eingebettetes Workflow 2.26 | PHP 8.2+ in 8.x; PHP 8.3+ für Laravel 13 | `^12.69.0` oder `^13.30.0` | | Eingebettetes Workflow 2.20.5 | PHP `^8.1`, zusätzlich gilt das Framework-Minimum | `^10.50.4`, `^11.56.1`, `^12.69.0` oder `^13.30.0` | | Veröffentlichtes PHP-SDK 3.14 | Reines SDK PHP `^8.1`; die Laravel-Bridge benötigt PHP `^8.2` und für Laravel 13 PHP 8.3+ | `^12.69.0` oder `^13.30.0` | | PHP-SDK 3.9.5 | Reines SDK PHP `^8.1`; die Laravel-Bridge beachtet ebenfalls das Framework-Minimum | `^10.50.4`, `^11.56.1`, `^12.69.0` oder `^13.30.0` | -Maßgeblich sind der [veröffentlichte eingebettete Upgrade-Vertrag](https://github.com/durable-workflow/workflow/blob/2.24.0/resources/laravel-embedded-upgrade-contract.json) +Maßgeblich sind der [veröffentlichte eingebettete Upgrade-Vertrag](https://github.com/durable-workflow/workflow/blob/2.26.0/resources/laravel-embedded-upgrade-contract.json) und die jeweilige `composer.json`. Das aktuelle eingebettete Release wurde mit Laravel 12/PHP 8.2–8.4 und Laravel 13/PHP 8.3–8.4 geprüft. Es entfernt PHP 8.1 und Laravel 10/11. Die [historische stabile v1-Anleitung](/docs/1.x/installation/) @@ -114,6 +114,16 @@ Workflow 2.23 und 2.24 behalten die Mindestanforderungen von 2.21 und das eingeb Siehe die Versionshinweise zu [2.23.0](https://github.com/durable-workflow/workflow/releases/tag/2.23.0), [2.23.1](https://github.com/durable-workflow/workflow/releases/tag/2.23.1), [2.23.2](https://github.com/durable-workflow/workflow/releases/tag/2.23.2) und [2.24.0](https://github.com/durable-workflow/workflow/releases/tag/2.24.0). +Workflow 2.25 und 2.26 behalten die Mindestanforderungen von 2.21 und das eingebettete Worker-Protokoll `1.22` bei. 2.25 fügt keine Datenbankmigration hinzu. 2.26 fügt eine hinzu, führen Sie beim Upgrade also `php artisan migrate` aus. Sie legt die Tabelle `workflow_child_supervisions` an. Vor dem Upgrade zu prüfende Änderungen: + +- Ab 2.26 übergibt ein Elternworkflow, der mit Continue-as-new fortgesetzt wird, während von ihm gestartete Kinder noch offen sind, diese an den fortgesetzten Lauf. Der letzte Lauf der Kette wendet ihre Parent-close-Richtlinie an, und ein fehlschlagendes Kind wird weiterhin nach seiner aufgezeichneten Wiederholungsrichtlinie wiederholt. Siehe [Continue-as-new und offene Kinder](./features/child-workflows.md#continue-as-new-and-open-children). +- Ab 2.26 sperren die Migrationen früherer Releases, die bestehende Zeilen befüllen (`2026_07_13`, `2026_09_24`, `2026_09_29` und `2026_10_11`), die Tabelle nicht mehr für den gesamten Backfill. Sie fügen zuerst die Spalte hinzu, befüllen die Zeilen in kleinen Stapeln und bauen anschließend ihre Indizes auf, ohne Schreibzugriffe zu blockieren. Wird eine davon unterbrochen, führen Sie `php artisan migrate` erneut aus. Installationen, die sie bereits ausgeführt haben, sind nicht betroffen. +- Ab 2.26 verwendet Redrive einen untergeordneten Workflow wieder, der vor dem Fehler abgeschlossen wurde. Releases vor 2.26 spielen einen solchen Nachfolger nach dem wiederverwendeten Kind mit einer anderen Workflow-Zeit ab. Halten Sie Worker daher auf 2.26 oder neuer, sobald ein solcher existiert. Siehe [Fehlgeschlagenen Lauf per Redrive fortsetzen](./failures-and-recovery.md#redrive). +- Ab 2.26 lesen `historyBudgetAtStep()` und `shouldContinueAsNewAtStep()` das Historienbudget bei jedem Replay gleich. Verwenden Sie sie in Schleifen. Siehe [Historienbudget](./features/continue-as-new.md#history-budget). +- Ab 2.25 löst das Überschreiten einer festen Obergrenze für Memos oder Suchattribute `StructuralLimitExceededException` statt `InvalidArgumentException` aus, und der Standardwert von `memo_size_bytes` ist 65.536. Siehe [Strukturelle Grenzen](./constraints/structural-limits.md). + +Siehe die Versionshinweise zu [2.25.0](https://github.com/durable-workflow/workflow/releases/tag/2.25.0) und [2.26.0](https://github.com/durable-workflow/workflow/releases/tag/2.26.0). + ## Stabilitätsstufen {#stability-levels} Jede öffentliche Durable-Workflow-Schnittstelle trägt genau eine dieser Stabilitätsstufen. Die Stufen sind explizit: Eine nicht klassifizierte Schnittstelle ist nicht öffentlich. diff --git a/i18n/de/docusaurus-plugin-content-docs/current/defining-workflows/workflow-api.md b/i18n/de/docusaurus-plugin-content-docs/current/defining-workflows/workflow-api.md index f68d7f90a56..d216c72521c 100644 --- a/i18n/de/docusaurus-plugin-content-docs/current/defining-workflows/workflow-api.md +++ b/i18n/de/docusaurus-plugin-content-docs/current/defining-workflows/workflow-api.md @@ -50,6 +50,8 @@ abstract class Workflow public function historyLength(): int; public function historySize(): int; public function shouldContinueAsNew(): bool; + public function historyBudgetAtStep(): array; + public function shouldContinueAsNewAtStep(): bool; } ``` @@ -62,6 +64,8 @@ abstract class Workflow | `historyLength()` | Der Workflow einen anzahlbasierten Hinweis auf sein Historienbudget benötigt. | Aktuelle Anzahl der Historienereignisse. | | `historySize()` | Der Workflow einen bytebasierten Hinweis auf sein Historienbudget benötigt. | Ungefähre Größe der gespeicherten Historie in Bytes. | | `shouldContinueAsNew()` | Der Workflow vor zu hohen Historienkosten einen neuen Lauf beginnen sollte. | `true`, wenn die konfigurierten Historienbudgets einen Wechsel empfehlen. | +| `historyBudgetAtStep()` | Der Workflow das Budget in einem Lauf mehrmals liest, etwa in einer Schleife (Workflow 2.26+). | Budgetzähler zum aktuellen Schritt, bei jedem Replay gleich. | +| `shouldContinueAsNewAtStep()` | Eine Schleife entscheidet, ob ein neuer Lauf beginnen soll (Workflow 2.26+). | `true`, wenn die Historie vor dem aktuellen Schritt ein konfiguriertes Budget überschreitet. | ## Dauerhafte Befehle {#durable-commands} diff --git a/i18n/de/docusaurus-plugin-content-docs/current/failures-and-recovery.md b/i18n/de/docusaurus-plugin-content-docs/current/failures-and-recovery.md index 7d648543af2..8295f2c616d 100644 --- a/i18n/de/docusaurus-plugin-content-docs/current/failures-and-recovery.md +++ b/i18n/de/docusaurus-plugin-content-docs/current/failures-and-recovery.md @@ -114,6 +114,7 @@ Der Nachfolger spielt den Workflow-Code von Anfang an erneut ab: - Ein Memo oder Suchattribut, das der Workflow-Code vor dem fehlgeschlagenen Schritt per Upsert gesetzt hat, wird in Schrittreihenfolge wiederverwendet, und der Nachfolger behält dieselben Werte. - Eine Signalwarteoperation (`await('name')`), die ihr Signal empfangen und angewendet hat, wird mit dem Wert des Signals wiederverwendet. Das Signal wird nicht erneut zugestellt. - Ein Update, das vor dem fehlgeschlagenen Schritt angenommen, angewendet und abgeschlossen wurde, wird an derselben Stelle erneut aufgezeichnet. Das Replay führt den Update-Handler mit den aufgezeichneten Argumenten aus, sodass der Zustand des Workflows übereinstimmt. Das Update wird nicht erneut zugestellt. Ein abgelehntes Update und eines, das der Fehler vor seiner Ausführung geschlossen hat, werden ausgelassen. +- In Workflow 2.26 und später liefert ein Child-Workflow-Aufruf, der vor dem fehlgeschlagenen Schritt abgeschlossen wurde, sein aufgezeichnetes Ergebnis. Das Child wird nicht erneut gestartet. Der Nachfolger zeichnet die Ereignisse `ChildWorkflowScheduled`, `ChildRunStarted` und `ChildRunCompleted` des Aufrufs auf und behält die ursprüngliche Child-Instanz, den Child-Lauf, die Link-ID und die Call-ID, erhält aber keine eigene Child-Verknüpfung. - `outbox()->sendReference()` und `inbox()->receive()` in wiederverwendetem Workflow-Code geben die Nachricht zurück, die der fehlgeschlagene Lauf gesendet oder konsumiert hat. Sie senden oder konsumieren sie nicht erneut. Ein Receive im Replay, dessen ursprünglicher Aufruf nichts gefunden hat, liest den Stream erneut. - In Workflow 2.20.2 und später gehen eingehende Stream-Nachrichten, die auf dem fehlgeschlagenen Lauf noch ausstehen, auf den Nachfolger über. Workflow 2.20.1 und früher ließen sie auf dem fehlgeschlagenen Lauf, sodass der Nachfolger sie nie erhielt ([workflow#1013](https://github.com/durable-workflow/workflow/issues/1013)). - Wenn ein Aktivitätsfehler den Lauf beendet hat, wird der fehlgeschlagene Aktivitätsaufruf als neue Aktivitätsausführung mit der Wiederholungsrichtlinie aus dem Workflow-Code eingeplant. Seine Versuche beginnen von vorn. @@ -123,7 +124,7 @@ Der Nachfolger spielt den Workflow-Code von Anfang an erneut ab: - Der Nachfolger übernimmt die Ausführungsfrist des fehlgeschlagenen Laufs. Sein Lauf-Zeitlimit beginnt beim Redrive neu. - Jeder wiederverwendete Schritt trägt `reused_from_run_id` und `reused_recorded_at`. Bei einem wiederverwendeten Update- oder Signalereignis treten die beiden immer als Paar auf. - Ein Nachfolger, der Schritte wiederverwendet hat, kann erneut per Redrive fortgesetzt werden. Ein wiederverwendeter Signal- oder Update-Payload behält in `workflow_run_id` den Lauf, der ihn zuerst aufgezeichnet hat, `reused_from_run_id` nennt den Lauf, aus dem er per Redrive hervorging, und jeder wiederverwendete Schritt behält den Zeitpunkt seiner ersten Ausführung. So verwendet eine Kette von Redrives jeden Schritt nur einmal wieder. -- Im Embedded-Modus beginnt `Workflow::now()` im Nachfolger bei der Startzeit des fehlgeschlagenen Laufs. Das Replay verwendet `reused_recorded_at`. Deshalb entspricht `Workflow::now()` nach einem wiederverwendeten Schritt der Zeit im fehlgeschlagenen Lauf. Ein Schritt, den ein zweiter Redrive wiederverwendet, behält den Zeitpunkt seiner ersten Ausführung. +- Im Embedded-Modus beginnt `Workflow::now()` im Nachfolger bei der Startzeit des fehlgeschlagenen Laufs. Das Replay verwendet `reused_recorded_at`. Deshalb entspricht `Workflow::now()` nach einem wiederverwendeten Schritt der Zeit im fehlgeschlagenen Lauf. Nach einem wiederverwendeten Child-Workflow-Aufruf ist das der Zeitpunkt, zu dem das Child ursprünglich abgeschlossen wurde. Ein Schritt, den ein zweiter Redrive wiederverwendet, behält den Zeitpunkt seiner ersten Ausführung. ### Redrive anfordern {#request-a-redrive} @@ -179,11 +180,12 @@ Redrive nimmt einen fehlgeschlagenen Lauf an, wenn alle folgenden Bedingungen er - Der Lauf ist der aktuelle Lauf der Instanz. - Der Lauf ist fehlgeschlagen, weil ein Aktivitätsfehler den Workflow-Code erreicht hat und nicht abgefangen wurde, oder weil der Workflow-Code eine Exception ausgelöst hat oder ein strukturelles Limit ihn gestoppt hat. Ein Lauf, der an einem Workflow-Zeitlimit fehlgeschlagen ist, wird abgelehnt. -- Jeder Schritt vor dem fehlgeschlagenen Schritt ist eine abgeschlossene Aktivität, ein Seiteneffekt, ein Versionsmarker, ein ausgelöster `timer()`, ein Upsert eines Memos oder Suchattributs, eine Signalwarteoperation, die ihr Signal empfangen und angewendet hat, oder ein Update, das mit denselben Argumenten angenommen, angewendet und abgeschlossen wurde. Ein abgelehntes Update und eines, das der Fehler vor seiner Ausführung geschlossen hat, sind erlaubt und werden ausgelassen. Payloads von Aktivitäten, Seiteneffekten, Signalen und Updates müssen inline gespeichert sein. Ein Payload im externen Payload-Speicher wird abgelehnt. +- Jeder Schritt vor dem fehlgeschlagenen Schritt ist eine abgeschlossene Aktivität, ein Seiteneffekt, ein Versionsmarker, ein ausgelöster `timer()`, ein Upsert eines Memos oder Suchattributs, eine Signalwarteoperation, die ihr Signal empfangen und angewendet hat, ein Update, das mit denselben Argumenten angenommen, angewendet und abgeschlossen wurde, oder, in Workflow 2.26 und später, ein abgeschlossener Child-Workflow-Aufruf. Ein abgelehntes Update und eines, das der Fehler vor seiner Ausführung geschlossen hat, sind erlaubt und werden ausgelassen. Payloads von Aktivitäten, Seiteneffekten, Signalen, Updates und Child-Ergebnissen müssen inline gespeichert sein. Ein Payload im externen Payload-Speicher wird abgelehnt. - Die Workflow-Definition entspricht dem Fingerprint, der beim Start des Laufs aufgezeichnet wurde, oder Sie haben `allow_definition_change` übergeben und der korrigierte Code spielt die abgeschlossenen Schritte erneut ab. Ein Fehler im Workflow-Code bei unveränderter Definition wird abgelehnt. - Die Ausführungsfrist ist nicht abgelaufen. -- Der Lauf hat keinen übergeordneten Workflow, keine Child-Workflows und keine lokalen Aktivitäten, und seine Eingabe ist inline gespeichert. -- Wenn ein Service-Worker den Lauf gestartet hat, bestehen die Schritte vor dem Fehler nur aus Aktivitäten, Seiteneffekten, Versionsmarkern und ausgelösten Timern. Memo- und Suchattribut-Upserts, Signalwarteoperationen und angewendete Updates werden für Läufe im Servicemodus abgelehnt. +- Der Lauf hat keinen übergeordneten Workflow und keine lokalen Aktivitäten, und seine Eingabe ist inline gespeichert. Vor Workflow 2.26 hat er außerdem keine Child-Workflows. Ein Lauf, der selbst ein Child ist, wird nie per Redrive fortgesetzt, weil sein übergeordneter Workflow das Ergebnis des Childs bereits aufgezeichnet hat. +- Jeder Child-Workflow-Aufruf vor dem fehlgeschlagenen Schritt wurde eigenständig abgeschlossen, außerhalb einer parallelen Gruppe oder eines Cancellation Scope, ohne Wiederholung und ohne Continue-as-new. +- Wenn ein Service-Worker den Lauf gestartet hat, bestehen die Schritte vor dem Fehler nur aus Aktivitäten, Seiteneffekten, Versionsmarkern und ausgelösten Timern. Memo- und Suchattribut-Upserts, Signalwarteoperationen, angewendete Updates und abgeschlossene Child-Workflow-Aufrufe werden für Läufe im Servicemodus abgelehnt. Eine Ablehnung nennt die erste Regel, die nicht erfüllt ist: @@ -193,7 +195,12 @@ Eine Ablehnung nennt die erste Regel, die nicht erfüllt ist: | `source_run_not_current` | Es gibt einen neueren Lauf der Instanz. | | `unrecorded_failure_boundary` | Für den Fehler des Laufs ist kein Schritt aufgezeichnet, etwa bei einem Fehler im Workflow-Code, den ein Release vor 2.19.0 aufgezeichnet hat. | | `workflow_code_failure_requires_corrected_definition` | Der Workflow-Code hat eine Exception ausgelöst, und die Definition hat sich nicht geändert. Derselbe Code würde also erneut eine Exception auslösen. | -| `unsupported_history` | Die Historie vor dem Fehler enthält einen Schritt, den Redrive nicht wiederverwenden kann, etwa einen Child-Workflow oder einen abgebrochenen Timer. | +| `unsupported_history` | Die Historie vor dem Fehler enthält einen Schritt, den Redrive nicht wiederverwenden kann, etwa einen abgebrochenen Timer. Vor Workflow 2.26 jeden Child-Workflow. | +| `unsupported_open_child` | Ein Child-Workflow-Aufruf vor dem Fehler wurde nie geschlossen. Workflow 2.26 und später. | +| `unsupported_child_outcome` | Ein Child-Workflow vor dem Fehler ist fehlgeschlagen, wurde abgebrochen oder beendet. Workflow 2.26 und später. | +| `unsupported_child_workflow` | Ein Child-Workflow-Aufruf liegt in einer parallelen Gruppe oder einem Cancellation Scope, wurde wiederholt oder per Continue-as-new fortgesetzt, oder seine Ereignisse nennen nicht genau einen Child-Aufruf. Workflow 2.26 und später. | +| `external_child_result_not_supported` | Das Ergebnis eines abgeschlossenen Child-Workflows liegt im externen Payload-Speicher. Workflow 2.26 und später. | +| `unavailable_child_result` | Das Ergebnis eines abgeschlossenen Child-Workflows lässt sich nicht dekodieren. Workflow 2.26 und später. | | `unsupported_local_activity` | Die Historie enthält eine lokale Aktivität. | | `unsupported_timer` | Die Historie enthält einen Bedingungs- oder Signal-Timeout, einen Timer für die Abbruch-Bereinigung oder einen Timer in einem Cancellation Scope oder einer parallelen Gruppe. | | `incomplete_timer_step` | Einem Timer-Schritt fehlt das Ereignis für das Einplanen oder für das Auslösen. | @@ -220,7 +227,7 @@ Eine Ablehnung nennt die erste Regel, die nicht erfüllt ist: | `definition_incompatible_with_prefix` | Der korrigierte Code kann die abgeschlossenen Schritte nicht erneut abspielen. `definition_mismatch` nennt den ersten abweichenden Schritt. | | `definition_check_over_budget` | Die abgeschlossene Historie ist größer als das Historienbudget, das die Replay-Prüfung zulässt. | | `definition_change_requires_replay_check` | Ein Service-Worker hat den Lauf gestartet. Daher kann Redrive eine geänderte Definition nicht prüfen. | -| `service_redrive_history_not_qualified` | Ein Service-Worker hat den Lauf gestartet, und die Schritte vor dem Fehler enthalten einen Memo-Upsert, einen Suchattribut-Upsert, eine Signalwarteoperation oder ein angewendetes Update. Redrive lehnt diese Schritte für Läufe im Servicemodus ab, bis es für jede SDK-Laufzeit prüfen kann, ob sie diese Schritte per Replay verarbeiten kann. | +| `service_redrive_history_not_qualified` | Ein Service-Worker hat den Lauf gestartet, und die Schritte vor dem Fehler enthalten einen Memo-Upsert, einen Suchattribut-Upsert, eine Signalwarteoperation, ein angewendetes Update oder einen abgeschlossenen Child-Workflow-Aufruf. Redrive lehnt diese Schritte für Läufe im Servicemodus ab, bis es für jede SDK-Laufzeit prüfen kann, ob sie diese Schritte per Replay verarbeiten kann. | | `request_id_already_used` | Die `request_id` wurde bereits für einen anderen Redrive der Instanz verwendet. | | `already_redriven` | Wird von den Laufdetails und `describe()` für einen Lauf gemeldet, der bereits per Redrive fortgesetzt wurde. Eine Redrive-Anfrage dafür gibt stattdessen den vorhandenen Nachfolger zurück. | | `invalid_request_id` | Die `request_id` ist länger als 191 Zeichen. | @@ -242,6 +249,8 @@ In Workflow 2.20.0 und später melden die Laufdetails und `describe()` die Redri ### Frühere Releases und der native Server {#redrive-earlier-releases} +Workflow-Releases vor 2.26.0 lehnen jeden Child-Workflow in der Historie mit `unsupported_history` ab. Sie ignorieren `reused_recorded_at` bei Child-Workflow-Ereignissen, sodass ein 2.26.0-Nachfolger, der einen Child-Aufruf wiederverwendet hat, dort nach dem Aufruf mit einer anderen Workflow-Zeit und anderen Fristen abgespielt werden kann. Außerdem lehnen sie einen erneuten Redrive dieses Nachfolgers ab. Sobald ein solcher Nachfolger existiert, behalten Sie Worker ab 2.26.0 bei oder stellen Sie vor einem Rollback sicher, dass keine solche Historie per Replay verarbeitet werden kann. + Workflow 2.20.0 lehnt nichts ab, was 2.20.1 annimmt. In 2.20.0 sendet `outbox()->sendReference()` in wiederverwendetem Workflow-Code erneut, und ein `inbox()->receive()` im Replay kann andere oder keine Nachrichten zurückgeben oder eine neuere Nachricht konsumieren ([workflow#1010](https://github.com/durable-workflow/workflow/issues/1010)). Workflow 2.19.0 lehnt ein angewendetes Update ab (`unsupported_history`). Es lehnt außerdem den Redrive eines Nachfolgers ab, der ein Update (`unsupported_history`) oder eine Signalwarteoperation (`mismatched_signal_receipt`) wiederverwendet hat. Laufdetails und `describe()` zeigen Redrive-Verknüpfungen als diagnostischen Fallback. diff --git a/i18n/de/docusaurus-plugin-content-docs/current/features/child-workflows.md b/i18n/de/docusaurus-plugin-content-docs/current/features/child-workflows.md index b0a9b78c93d..e02f0faf42d 100644 --- a/i18n/de/docusaurus-plugin-content-docs/current/features/child-workflows.md +++ b/i18n/de/docusaurus-plugin-content-docs/current/features/child-workflows.md @@ -232,7 +232,7 @@ $results = all([ - Schließt der Elternlauf aus irgendeinem Grund, sucht die Engine offene Kindverknüpfungen mit einer anderen Richtlinie als Abandon und sendet jedem offenen Kind den passenden Befehl (kooperativen Abbruch anfordern, abbrechen oder beenden). - Ist das Kind bei der Durchsetzung bereits geschlossen, geschieht nichts. Der Befehl wird still übersprungen. - Die Durchsetzung erfolgt nach bestem Bemühen: Wird ein Kindbefehl abgelehnt, etwa weil das Kind bereits endgültig geschlossen ist, beeinflusst dies den Abschluss des Elternlaufs nicht. Bei erfolgreicher Durchsetzung wird dort `ParentClosePolicyApplied` aufgezeichnet. Bei fehlgeschlagener Durchsetzung entsteht stattdessen `ParentClosePolicyFailed`, damit Betreiber Erfolg von stillen Fehlern unterscheiden können. -- Continue-as-new löst die Parent-close-Richtlinie **nicht** aus, da die Workflow-Instanz unter einem neuen Lauf aktiv bleibt. +- Continue-as-new löst die Parent-close-Richtlinie **nicht** aus, da die Workflow-Instanz unter einem neuen Lauf aktiv bleibt. Ab Workflow 2.26 wendet stattdessen der letzte Lauf der Kette sie an. Siehe [Continue-as-new und offene Kinder](#continue-as-new-and-open-children). ### Matrix der Elternlauf-Ergebnisse {#parent-disposition-matrix} @@ -249,9 +249,21 @@ Kindverknüpfung angewendet, die nicht Abandon verwendet. | Timeout | Ja | Nach Aufzeichnen von `WorkflowTimedOut` für Abschlüsse durch Lauf- oder Ausführungs-Timeout. | | Abgebrochen | Ja | Nachdem der angenommene Befehl `CancelRequested` den Elternlauf schließt. | | Beendet | Ja | Nachdem der angenommene Befehl `TerminateRequested` den Elternlauf schließt. | -| Continue-as-new | Nein | Die Workflow-Instanz bleibt unter dem neuen Lauf aktiv. Bestehende Kindverknüpfungen werden deshalb unter Erhalt ihrer ursprünglichen Richtlinie auf den fortgesetzten Lauf umgestellt. | +| Continue-as-new | Nein | Die Workflow-Instanz bleibt unter dem neuen Lauf aktiv. Ab Workflow 2.26 übernimmt der fortgesetzte Lauf die Überwachung der offenen Kinder, und der letzte Lauf der Kette wendet ihre Richtlinie an. | | Zurücksetzen | Derzeit nicht anwendbar | Die v2-Laufzeit bietet keinen eigenständigen Reset-Befehl oder endgültigen Reset-Zustand. Eine künftige Reset- oder Reparaturoperation, die einen Elternlauf schließt oder ersetzt, muss definieren, ob die Kindverantwortung übergeht. Wird der alte Lauf endgültig geschlossen, muss er die Parent-close-Richtlinie anwenden, bevor er die Verantwortung für offene Kinder abgibt. | +### Continue-as-new und offene Kinder {#continue-as-new-and-open-children} + +In Workflow 2.26 und später übergibt ein Elternworkflow, der mit Continue-as-new fortgesetzt wird, während von ihm gestartete Kinder noch offen sind, diese in derselben Transaktion an den fortgesetzten Lauf. Eingebettete Läufe und Läufe im Servicemodus verhalten sich gleich: + +- Jedes offene Kind erhält eine Zeile in der Tabelle `workflow_child_supervisions`, die die Migration von 2.26 anlegt. Ein bereits geschlossenes Kind wird nicht weitergegeben. +- Kindverknüpfung, Kindaufruf, Sequenz, Fristen und Parent-close-Richtlinie bleiben so, wie der startende Lauf sie aufgezeichnet hat. Wird der fortgesetzte Lauf erneut mit Continue-as-new fortgesetzt, gibt er die Kinder wieder weiter. +- Wenn der letzte Lauf der Kette abgeschlossen wird, fehlschlägt, ein Timeout erreicht, abgebrochen oder beendet wird, wendet er die Richtlinie jedes Kindes an und zeichnet `ParentClosePolicyApplied` oder `ParentClosePolicyFailed` in seiner eigenen Historie auf. `abandon` bleibt `abandon`. Der geschlossene frühere Lauf erhält keine neue Historie. +- Der fortgesetzte Lauf hat keine Referenz auf diese Kinder, und ihre Ergebnisse werden ihm nicht zugestellt. Übergeben Sie alles, was der nächste Lauf benötigt, in den Argumenten von `continueAsNew()`. +- Ein weitergegebenes Kind, das fehlschlägt, wird nach der Wiederholungsrichtlinie wiederholt, die der startende Lauf aufgezeichnet hat, mit derselben Kindaufruf-Identität und demselben Versuchszähler, solange ein Lauf der Kette es noch überwacht. Das `WorkflowStarted` des Wiederholungslaufs nennt den startenden Lauf als Elternlauf, und der letzte Lauf der Kette wendet die Parent-close-Richtlinie auf den Wiederholungslauf an. Der Fehler ist endgültig, sobald die Versuche aufgebraucht sind, der Fehler nicht wiederholbar ist oder die Kette geschlossen wurde. + +Vor 2.26 liefen diese Kinder nach dem Schließen der Kette weiter, ihre Richtlinie wurde nie angewendet, und ein Kind, das nach dem Continue-as-new seines Elternworkflows fehlschlug, wurde nicht wiederholt. Siehe die [Versionshinweise zu 2.26.0](https://github.com/durable-workflow/workflow/releases/tag/2.26.0). + ### Wann welche Richtlinie geeignet ist {#when-to-use-each-policy} **Abandon** (Standard) eignet sich für unabhängige Arbeit, die ungeachtet des diff --git a/i18n/de/docusaurus-plugin-content-docs/current/features/continue-as-new.md b/i18n/de/docusaurus-plugin-content-docs/current/features/continue-as-new.md index a0c13508fa6..f1f1999f3c1 100644 --- a/i18n/de/docusaurus-plugin-content-docs/current/features/continue-as-new.md +++ b/i18n/de/docusaurus-plugin-content-docs/current/features/continue-as-new.md @@ -88,6 +88,18 @@ Historienlänge und ein Empfehlungssignal für Continue-as-new abfragen. Langlebige Schleifen können so bewusst übergeben, bevor sie an kostspielige Historienbudgetgrenzen stoßen. +In Workflow 2.26 und später verwenden Sie `shouldContinueAsNewAtStep()` und +`historyBudgetAtStep()`. Sie zählen nur die Historie, die vor dem aktuellen +Workflow-Schritt aufgezeichnet wurde, sodass dieselbe Zeile bei jedem Replay +dieselbe Antwort liefert. Eine Schleife, die das Budget in jeder Iteration +prüft, wird einmal mit Continue-as-new fortgesetzt, und zwar in der ersten +Iteration, die die Schwelle überschreitet. + +Die älteren Methoden lesen die gesamte aktuelle Historie. In einer Schleife kann +eine frühere Iteration beim Replay eine spätere Gesamtzahl sehen und einen +anderen Zweig nehmen als beim ersten Mal. Sie bleiben unverändert, damit Läufe, +die bereits mit ihnen entschieden haben, weiterhin abgespielt werden. + ```php use function Workflow\V2\activity; use function Workflow\V2\continueAsNew; @@ -115,6 +127,8 @@ class PollingWorkflow extends Workflow | `$this->historyLength()` | `int` | Anzahl der Historienereignisse im aktuellen Lauf | | `$this->historySize()` | `int` | Gesamtgröße der Historienereignisse in Bytes | | `$this->shouldContinueAsNew()` | `bool` | `true`, wenn der Lauf das konfigurierte Ereignisanzahl- oder Byte-Größenbudget überschreitet | +| `$this->historyBudgetAtStep()` | `array` | Das Budget zum aktuellen Schritt: `history_event_count`, `history_size_bytes`, `history_fan_out`, `continue_as_new_recommended`, `pressure`, `pressure_dimensions` und `observation` (`step_prefix.v1`). Workflow 2.26 und später. | +| `$this->shouldContinueAsNewAtStep()` | `bool` | `continue_as_new_recommended` aus `historyBudgetAtStep()`. Verwenden Sie es in Schleifen. Workflow 2.26 und später. | ### Konfiguration {#configuration} @@ -130,7 +144,7 @@ Die Empfehlungsschwellen für Continue-as-new sind konfigurierbar: ], ``` -`shouldContinueAsNew()` gibt `true` zurück, wenn eine der Schwellen +`shouldContinueAsNew()` und `shouldContinueAsNewAtStep()` geben `true` zurück, wenn eine der Schwellen überschritten wird. Laufzusammenfassungen führen auch `history_event_count`, `history_size_bytes` und `continue_as_new_recommended`, damit Waterline langlebige Läufe in Flottenansichten kennzeichnen kann. @@ -176,6 +190,10 @@ class PollingWorkflow extends Workflow } ``` +Ein Elternworkflow, der mit Continue-as-new fortgesetzt wird, während von ihm +gestartete Child-Workflows noch offen sind, übergibt diese an den fortgesetzten +Lauf. Siehe [Continue-as-new und offene Kinder](./child-workflows.md#continue-as-new-and-open-children). + Für langlebige Schleifen mit menschlichen Eingaben oder Assistenten bevorzugen Sie die vollwertige Fassade `$this->inbox()` / `$this->outbox()` für [Nachrichtenströme](./message-streams.md). Ausstehende Stromnachrichten und die diff --git a/i18n/de/docusaurus-plugin-content-docs/current/features/search-attributes.md b/i18n/de/docusaurus-plugin-content-docs/current/features/search-attributes.md index b858e2bf466..3751bea1038 100644 --- a/i18n/de/docusaurus-plugin-content-docs/current/features/search-attributes.md +++ b/i18n/de/docusaurus-plugin-content-docs/current/features/search-attributes.md @@ -120,7 +120,7 @@ Auf dem Server können Sie ein Suchattribut mit einem Typ über `POST /api/searc Die Registrierung schränkt nur die Schlüssel ein, die Sie registrieren. Ab dem nativen Server 3.5.0 wird ein nicht registrierter Schlüssel weiterhin angenommen und sein Typ abgeleitet, wie in einem Namespace ohne registrierte Attribute. Das Registrieren eines Attributs bricht keine laufenden Workflows, die andere Schlüssel upserten. PHP Server 2.x und der native Server vor 3.5.0 lehnen jeden nicht registrierten Schlüssel ab, sobald irgendein Attribut registriert ist. Registrieren Sie dort also alle Schlüssel, die Ihre Workflows verwenden, bevor Sie das erste registrieren. -Das Löschen einer Registrierung beendet die Prüfung dieses Schlüssels. Gespeicherte Werte und laufende Workflows bleiben unverändert, und spätere Upserts des Schlüssels werden wieder abgeleitet. +Das Löschen einer Registrierung beendet die Prüfung dieses Schlüssels. Gespeicherte Werte und laufende Workflows bleiben unverändert, und spätere Upserts des Schlüssels werden wieder abgeleitet. Auf dem nativen Server wird eine Listenabfrage, die nach einem nicht registrierten Schlüssel filtert, auch nach einem, dessen Registrierung Sie gelöscht haben, abgelehnt, weil der Schlüssel im Namespace nicht definiert ist. Um den Typ eines Attributs zu ändern, registrieren Sie einen neuen Attributnamen mit dem neuen Typ, passen Sie Ihre Workflows an, damit sie ihn schreiben, und filtern Sie nach dem neuen Namen, sobald bestehende Ausführungen nachgezogen haben. Wenn Sie denselben Namen löschen und mit einem anderen Typ neu registrieren, behalten frühere Werte den alten Typ. diff --git a/i18n/de/docusaurus-plugin-content-docs/current/polyglot/php.md b/i18n/de/docusaurus-plugin-content-docs/current/polyglot/php.md index c1f2253e3b1..a4e5e83e0d3 100644 --- a/i18n/de/docusaurus-plugin-content-docs/current/polyglot/php.md +++ b/i18n/de/docusaurus-plugin-content-docs/current/polyglot/php.md @@ -305,7 +305,7 @@ Neu in diesen Versionen: - **Sticky-History-Suffixe (3.14).** Worker melden `sticky_history_suffix`. Auf Server 3.5.0 oder neuer erhält ein Worker, der die Historie einer Ausführung bereits hält, nur die Ereignisse nach der zwischengespeicherten Sequenz. Ein Suffix, das die zwischengespeicherte Historie nicht exakt fortsetzt, wird verworfen und die vollständige Historie abgerufen. Ältere Server senden weiterhin die vollständige Historie. - **Zeitplanursprung (3.13).** `WorkflowContext::scheduleOrigin()` liefert die Zeitplan-ID, den Auslösezeitpunkt und die Auslösenummer des Zeitplanlaufs, der die Ausführung gestartet hat, oder `null` bei einem gewöhnlichen Start. Der Wert ist beim Replay derselbe. Ab Server 3.5.0 behält eine mit Continue-as-new fortgesetzte Ausführung ihren Zeitplanursprung. -- **Aktivitätsfortsetzungen (3.12).** Übergeben Sie dem `Worker`-Konstruktor `enableActivityContinuation: true`, um die nächsten Workflow-Befehle zusammen mit einem erfolgreichen Aktivitätsergebnis zu senden, wenn der Server `activity_workflow_continuation` meldet (nativer Server 3.4.0 oder neuer). Standard ist `false`. Verwenden Sie 3.12.1 oder neuer, wenn Sie es aktivieren, und leeren oder deaktivieren Sie solche Worker, bevor Sie den Server zurückstufen oder ältere Server-Knoten hinzufügen. +- **Aktivitätsfortsetzungen (3.12).** Übergeben Sie dem `Worker`-Konstruktor `enableActivityContinuation: true`, um die nächsten Workflow-Befehle zusammen mit einem erfolgreichen Aktivitätsergebnis zu senden, wenn der Server `activity_workflow_continuation` meldet (nativer Server 3.4.0 oder neuer). Standard ist `false`. Das Aktivieren kostet derzeit Durchsatz: In unserem Benchmark unter Last liefen Workflows damit 24–49 % langsamer und benötigten doppelt so viele Datenbanktransaktionen ([Messung](https://github.com/durable-workflow/server/issues/1078)). Verwenden Sie 3.12.1 oder neuer, wenn Sie es aktivieren, und leeren oder deaktivieren Sie solche Worker, bevor Sie den Server zurückstufen oder ältere Server-Knoten hinzufügen. Die vollständige Liste steht im [Changelog zu 3.14.0](https://github.com/durable-workflow/sdk-php/blob/3.14.0/CHANGELOG.md). diff --git a/i18n/de/docusaurus-plugin-content-docs/current/testing.md b/i18n/de/docusaurus-plugin-content-docs/current/testing.md index 4e2d869bbeb..b263957161c 100644 --- a/i18n/de/docusaurus-plugin-content-docs/current/testing.md +++ b/i18n/de/docusaurus-plugin-content-docs/current/testing.md @@ -357,7 +357,7 @@ Beide Richtlinien zeichnen dauerhafte Befehls- und Historienereignisse auf. Für ### Historienbudget testen {#testing-history-budget} -Die Felder von `HistoryBudget` (`history_event_count`, `history_size_bytes`, `continue_as_new_recommended`) erscheinen in der Zusammenfassungsprojektion des Laufes und sind über `RunDetailView` verfügbar. Im Workflow-Code stellt die Basisklasse `Workflow` sie als `$this->historyLength()`, `$this->historySize()` und `$this->shouldContinueAsNew()` bereit: +Die Felder von `HistoryBudget` (`history_event_count`, `history_size_bytes`, `continue_as_new_recommended`) erscheinen in der Zusammenfassungsprojektion des Laufes und sind über `RunDetailView` verfügbar. Im Workflow-Code stellt die Basisklasse `Workflow` sie als `$this->historyLength()`, `$this->historySize()` und `$this->shouldContinueAsNew()` bereit. Verwenden Sie in einer Schleife `$this->shouldContinueAsNewAtStep()` (Workflow 2.26 und später), das bei jedem Replay dieselbe Antwort liefert: ```php use Workflow\V2\Workflow; @@ -369,7 +369,7 @@ final class LongRunningWorkflow extends Workflow while (true) { // ... process work ... - if ($this->shouldContinueAsNew()) { + if ($this->shouldContinueAsNewAtStep()) { Workflow::continueAsNew($this->carryForwardState()); } } diff --git a/i18n/de/source-hashes.json b/i18n/de/source-hashes.json index aaa9e3d33f5..29802b30c7c 100644 --- a/i18n/de/source-hashes.json +++ b/i18n/de/source-hashes.json @@ -4,7 +4,7 @@ "ai-agent-workflow-engine.md": "28016466b179adbabdff6467ce351100c9bee48529a8bec9df7ec22c8d786d4d", "ai-assisted-development.md": "b246bb60585fb7a69bc534978f470f3f16e899e1f8f203ba0847d2d11b8a1ec3", "capabilities.md": "d9a2bbc0d04adf8cb3f4c7f42d779a43aafab60791210305e7e476c0499528fc", - "compatibility.md": "567310faf420fbd5229c5eef69721e8b7d09f033333cbaec21b72acaf81b6690", + "compatibility.md": "ad5c8519be03ae1e7b6e5e03b05a886862fd67c603b241ecb5baf2be5cd59610", "configuration/customization-matrix.md": "3d115863eaee7852b541bcd01615f424cc19c5847c7cd7d75e5ae63bc3f5cc78", "configuration/database-connection.md": "cc83ae77133236309506fa44d39bfd0c939c32a6154c0bd6099bc64c83bdaec9", "configuration/ensuring-same-server.md": "6c665f37cc198c7b1a775a60a94aab5ff4e55383385e76f1834c7840559b512a", @@ -24,18 +24,18 @@ "defining-workflows/activities.md": "05b46f73477a0bbd5f21d17ac37def8a8eac53f1e629155805c98cc46e75b418", "defining-workflows/passing-data.md": "c5d36126b0b15f1780119f6418e8bbe5a63e03353be5a0bb69385206ef0ad635", "defining-workflows/starting-workflows.md": "722b80454b577b0715ff50db70c7cda2cd02c34c505dd1219a83307852d325a4", - "defining-workflows/workflow-api.md": "a6150e75302323b49f350159ce3568a51a19701bb81829915615f754592ee79c", + "defining-workflows/workflow-api.md": "3c13894c1fdbe77bb1379c62bbdb0ef213c81f1cba5b477d45402dcc7fe87237", "defining-workflows/workflow-id.md": "ca3b43253a748b27dca1af9f82fcf8c4c133e14f13e1b82eaa1ca2ed0996d4bf", "defining-workflows/workflow-status.md": "8e8cb27ff44c890d489d89bf166375acfdfaecabd990a2235e106fab1592d529", "defining-workflows/workflows.md": "f467bc73de32aa5d722c61ce085065460382ae7dd44cea4625847d9fcdc4c97c", "deployment.md": "6aa439b1ebfdc2affccaf6fe6fff7519776a4ffcad8d3cb5956b665e7c97257f", - "failures-and-recovery.md": "598b538e2bcb6a40a4f2d4c0c462705bab30ef96767144f6590c2cc93b68a98a", + "failures-and-recovery.md": "4209521a8783939d458658a7afea64124c34571080c97feb2868a273db88db3e", "features/activity-execution-model.md": "e8c37520ae46a7efb30438f4fc06bf893c1df430cb1f92c48963697adaf09082", "features/cancel-and-terminate.md": "cedd1e6c51dfa551e00edc1d39739ff1f67d558d2a0be92143f478cb6111536b", - "features/child-workflows.md": "57016591fb8816aed7b077e204f1c80f9c6a8dff7501bc00a141c41a4607306b", + "features/child-workflows.md": "278b634b8b48b94203309cdba27d6116897a2919cab19628add8cd85dadb08d3", "features/concurrency.md": "a7a3eb2274f7b14faf722494569b7663c07ab48afdf2e9225e58914b84cacbb4", "features/condition-waits.md": "451261eda990c9591a0db69839d872184b5c64da6b537a582133095b8d4b599e", - "features/continue-as-new.md": "50c79f317155e052a3f2f37d198a71bdfc496a454905293f40cf09d73138f25b", + "features/continue-as-new.md": "a5309192c685abeb5295071d423824ae2287e68d247a6661f18d3ab21f9bdc9c", "features/events.md": "c466df05908748489226a3d1410c9203cf6f2986a4bb7539db1c5f82715abc7b", "features/external-payload-storage.md": "acc312fa2f50a43c96e1d235439124d28a7048f0bf3abac34319467fcbf7e898", "features/heartbeats.md": "4fce9636d68c89f29f259d52e463cd67eccf0bc55ad4d53338ed03329892b365", @@ -45,7 +45,7 @@ "features/queries.md": "c66dd9542a062edd8158a46cebc9f1bf926aaf3599dca4a3122bd9860df6e2a2", "features/sagas.md": "046ba5661ccb5ac71a236356d243b021d9830123e3798afce491118434e83820", "features/schedules.md": "40d30b2767e7ed043e2b0c7180915c256accea3e7a3401c38d1bf75bfe1c2213", - "features/search-attributes.md": "567d89858cd82e86672b210154001a272b17a5f87e13dbfa7de1b8e093d615b8", + "features/search-attributes.md": "bb66d83f64e0098354d86ac237e6867b9819098044101ba9a60a6a00a3961dd1", "features/service-operations.md": "912131c0a8ef393040a933fb4a66e68abcb9d475a3ebd47c85287d4032f45a0e", "features/side-effects.md": "abdccab8d6fc1a12b3eff8a4ccc58730ac36f523559b4ad89c5c2a8d201a3b86", "features/signal+timer.md": "a05fc480544fa71f6c9b215ad3417f71b8475dd81f9de8ee18d7a3b69ac33a23", @@ -80,7 +80,7 @@ "polyglot/invocable-carrier.md": "d32d8b5c7c33204b342f977e0af734166d91e96073db1a49ccb4d414a6d67380", "polyglot/invocable-php-handler.md": "3b678eb1d69fe32dfcfdc05d36b33e49e01b79d7216bd784f6a61a6f1c3c3a13", "polyglot/namespace-auth-workers.md": "2b4078ceb74b849f12cb1975b410ff8e7266cd4345f6cf1d4dd906db12460ffb", - "polyglot/php.md": "04f7eeebf842bbcd2f278f96ee21fbbf4f97d424a27e717d65e1c73273bce095", + "polyglot/php.md": "309e83622754b9d9abc65807280f2dab175a009054a001456ef1316776f11101", "polyglot/polling-patterns.md": "30875099a23731c6c471b481a771378acc6ff57eed2fda4405a509057534c989", "polyglot/portable-worker-affinity.md": "40973c6a31a76845b4f95e9a505e68ad76abd5174bbdccf37993cdebc8904959", "polyglot/prerelease-history-migration.md": "a57f05f492228a8a67791f9152648a1e5f80856325b78777cf63b6ef49b7413c", @@ -105,6 +105,6 @@ "sdk-neutrality.md": "7b0714c123ade4904591870fc20e9a797da1e5485b2a6c87ca3eaa00c5de6ed6", "sponsors.md": "e85e14375743ca8fa50e3a48f894b160e28272573aa88480064f74010ebee98a", "support.md": "706807b3902599dda6080f632ec1f893017ea18bbe9585f533dcdbd6d85f4621", - "testing.md": "250bc7dfd46f99eaeb392b329947813b064bda72026645198e3aefc80043a813", + "testing.md": "176abf226936c7711c2df523fb8a94e92fcf62e6f804d99f2e32b9135f626547", "waterline-operator-api.md": "2aca03b2c14100060b40be0bb033a82525ba924908834e9060ec746ead26f36d" } diff --git a/i18n/es/docusaurus-plugin-content-docs/current/compatibility.md b/i18n/es/docusaurus-plugin-content-docs/current/compatibility.md index 33e27a9afbe..090a506cc6f 100644 --- a/i18n/es/docusaurus-plugin-content-docs/current/compatibility.md +++ b/i18n/es/docusaurus-plugin-content-docs/current/compatibility.md @@ -100,12 +100,12 @@ El paquete integrado y el SDK de modo servicio tienen contratos distintos. | Línea del paquete | PHP | Laravel | | --- | --- | --- | -| Workflow integrado 2.24 actual | PHP 8.2+ de 8.x; PHP 8.3+ para Laravel 13 | `^12.69.0` o `^13.30.0` | +| Workflow integrado 2.26 actual | PHP 8.2+ de 8.x; PHP 8.3+ para Laravel 13 | `^12.69.0` o `^13.30.0` | | Workflow integrado 2.20.5 | PHP `^8.1`, sujeto al mínimo del framework | `^10.50.4`, `^11.56.1`, `^12.69.0` o `^13.30.0` | | SDK PHP 3.14 publicado | SDK básico PHP `^8.1`; el puente Laravel necesita PHP `^8.2`, y PHP 8.3+ para Laravel 13 | `^12.69.0` o `^13.30.0` | | SDK PHP 3.9.5 | SDK básico PHP `^8.1`; el puente Laravel también exige el mínimo del framework | `^10.50.4`, `^11.56.1`, `^12.69.0` o `^13.30.0` | -Las autoridades son el [contrato integrado publicado](https://github.com/durable-workflow/workflow/blob/2.24.0/resources/laravel-embedded-upgrade-contract.json) +Las autoridades son el [contrato integrado publicado](https://github.com/durable-workflow/workflow/blob/2.26.0/resources/laravel-embedded-upgrade-contract.json) y el `composer.json` de cada versión. La versión integrada actual se verificó con Laravel 12/PHP 8.2–8.4 y Laravel 13/PHP 8.3–8.4. Retira PHP 8.1 y Laravel 10/11. No cambia la [guía histórica de v1 estable](/docs/1.x/installation/) @@ -147,6 +147,16 @@ Workflow 2.23 y 2.24 mantienen los mínimos de soporte de 2.21 y el protocolo de Consulte las notas de versión de [2.23.0](https://github.com/durable-workflow/workflow/releases/tag/2.23.0), [2.23.1](https://github.com/durable-workflow/workflow/releases/tag/2.23.1), [2.23.2](https://github.com/durable-workflow/workflow/releases/tag/2.23.2) y [2.24.0](https://github.com/durable-workflow/workflow/releases/tag/2.24.0). +Workflow 2.25 y 2.26 mantienen los mínimos de soporte de 2.21 y el protocolo de workers integrado `1.22`. 2.25 no añade ninguna migración de base de datos. 2.26 añade una, así que ejecute `php artisan migrate` al actualizar. Crea la tabla `workflow_child_supervisions`. Cambios que conviene revisar antes de actualizar: + +- Desde 2.26, un padre que continúa como nueva ejecución mientras los hijos que inició siguen abiertos los entrega a la ejecución continuada. La ejecución final de la cadena aplica su política de cierre del padre, y un hijo que falla se sigue reintentando con su política de reintentos registrada. Consulte [Continuar como nueva ejecución e hijos abiertos](./features/child-workflows.md#continue-as-new-and-open-children). +- Desde 2.26, las migraciones de versiones anteriores que rellenan filas existentes (`2026_07_13`, `2026_09_24`, `2026_09_29` y `2026_10_11`) ya no bloquean la tabla durante todo el relleno. Primero añaden la columna, rellenan las filas en lotes pequeños y después crean sus índices sin bloquear las escrituras. Si una de ellas se interrumpe, vuelva a ejecutar `php artisan migrate`. Las instalaciones que ya las ejecutaron no se ven afectadas. +- Desde 2.26, el redrive reutiliza un workflow hijo que se completó antes del fallo. Las versiones anteriores a 2.26 reproducen esa sucesora con una hora del workflow distinta después del hijo reutilizado, así que mantenga los workers en 2.26 o posterior una vez que exista una. Consulte [Redrive de una ejecución fallida](./failures-and-recovery.md#redrive). +- Desde 2.26, `historyBudgetAtStep()` y `shouldContinueAsNewAtStep()` leen el presupuesto de historial de la misma forma en cada replay. Úselos en bucles. Consulte [Presupuesto de historial](./features/continue-as-new.md#history-budget). +- Desde 2.25, superar un límite fijo de memo o de atributo de búsqueda lanza `StructuralLimitExceededException` en lugar de `InvalidArgumentException`, y el valor predeterminado de `memo_size_bytes` es 65.536. Consulte [Límites estructurales](./constraints/structural-limits.md). + +Consulte las notas de versión de [2.25.0](https://github.com/durable-workflow/workflow/releases/tag/2.25.0) y [2.26.0](https://github.com/durable-workflow/workflow/releases/tag/2.26.0). + ## Niveles de estabilidad {#stability-levels} Cada interfaz pública tiene exactamente uno de estos niveles de estabilidad. diff --git a/i18n/es/docusaurus-plugin-content-docs/current/defining-workflows/workflow-api.md b/i18n/es/docusaurus-plugin-content-docs/current/defining-workflows/workflow-api.md index 79a1aeceae8..99b03e3306d 100644 --- a/i18n/es/docusaurus-plugin-content-docs/current/defining-workflows/workflow-api.md +++ b/i18n/es/docusaurus-plugin-content-docs/current/defining-workflows/workflow-api.md @@ -54,6 +54,8 @@ abstract class Workflow public function historyLength(): int; public function historySize(): int; public function shouldContinueAsNew(): bool; + public function historyBudgetAtStep(): array; + public function shouldContinueAsNewAtStep(): bool; } ``` @@ -66,6 +68,8 @@ abstract class Workflow | `historyLength()` | El workflow necesita una señal del presupuesto de historial por cantidad. | Número actual de eventos de historial. | | `historySize()` | El workflow necesita una señal del presupuesto de historial por bytes. | Tamaño aproximado del historial guardado en bytes. | | `shouldContinueAsNew()` | El workflow debe rotar antes de encarecer el historial. | `true` cuando los presupuestos de historial configurados recomiendan rotar. | +| `historyBudgetAtStep()` | El workflow lee el presupuesto más de una vez en una ejecución, por ejemplo en un bucle (Workflow 2.26+). | Contadores del presupuesto en el paso actual, iguales en cada replay. | +| `shouldContinueAsNewAtStep()` | Un bucle decide si rotar (Workflow 2.26+). | `true` cuando el historial anterior al paso actual supera un presupuesto configurado. | ## Comandos duraderos {#durable-commands} diff --git a/i18n/es/docusaurus-plugin-content-docs/current/failures-and-recovery.md b/i18n/es/docusaurus-plugin-content-docs/current/failures-and-recovery.md index 44d06581b75..9571d98e16e 100644 --- a/i18n/es/docusaurus-plugin-content-docs/current/failures-and-recovery.md +++ b/i18n/es/docusaurus-plugin-content-docs/current/failures-and-recovery.md @@ -118,6 +118,7 @@ La sucesora vuelve a reproducir el código del workflow desde el principio: - Un memo o atributo de búsqueda del que el código del workflow hizo upsert antes del paso fallido se reutiliza en orden de pasos, y la sucesora conserva los mismos valores. - Una espera de señal (`await('name')`) que recibió y aplicó su señal se reutiliza con el valor de la señal. La señal no se vuelve a entregar. - Un update que se aceptó, se aplicó y se completó antes del paso fallido se vuelve a registrar en la misma posición. El replay ejecuta el handler del update con sus argumentos registrados, así que el estado del workflow coincide. El update no se vuelve a entregar. Un update rechazado, y uno que el fallo cerró antes de ejecutarse, se omiten. +- En Workflow 2.26 y versiones posteriores, una llamada a un workflow hijo que se completó antes del paso fallido devuelve su resultado registrado. El hijo no se vuelve a iniciar. La sucesora registra los eventos `ChildWorkflowScheduled`, `ChildRunStarted` y `ChildRunCompleted` de la llamada y conserva la instancia hija, la ejecución hija, el link id y el call id originales, pero no recibe un enlace hijo propio. - `outbox()->sendReference()` e `inbox()->receive()` en el código de workflow reutilizado devuelven el mensaje que la ejecución fallida envió o consumió. No lo vuelven a enviar ni a consumir. Un receive en replay cuya llamada original no encontró nada vuelve a leer el stream. - En Workflow 2.20.2 y versiones posteriores, los mensajes entrantes del stream que siguen pendientes en la ejecución fallida pasan a la sucesora. Workflow 2.20.1 y versiones anteriores los dejaban en la ejecución fallida, así que la sucesora nunca los recibía ([workflow#1013](https://github.com/durable-workflow/workflow/issues/1013)). - Si un fallo de actividad terminó la ejecución, la llamada de actividad fallida se programa como una ejecución de actividad nueva, con la política de reintentos del código del workflow. Sus intentos empiezan de nuevo. @@ -127,7 +128,7 @@ La sucesora vuelve a reproducir el código del workflow desde el principio: - La sucesora conserva el plazo de ejecución de la ejecución fallida. Su tiempo límite de ejecución vuelve a empezar en el redrive. - Cada paso reutilizado lleva `reused_from_run_id` y `reused_recorded_at`. En un evento reutilizado de update o de señal, los dos siempre van en pareja. - Un sucesor que reutilizó pasos puede volver a recibir un redrive. Un payload de señal o de update reutilizado conserva en `workflow_run_id` la ejecución que lo registró primero, `reused_from_run_id` indica la ejecución desde la que se hizo el redrive, y cada paso reutilizado conserva la hora en que se ejecutó por primera vez, así que una cadena de redrives reutiliza cada paso una sola vez. -- En modo embedded, `Workflow::now()` en la sucesora empieza en la hora de inicio de la ejecución fallida. La reproducción usa `reused_recorded_at`, así que `Workflow::now()` después de un paso reutilizado coincide con la hora de la ejecución fallida. Un paso reutilizado por un segundo redrive conserva la hora en que se ejecutó por primera vez. +- En modo embedded, `Workflow::now()` en la sucesora empieza en la hora de inicio de la ejecución fallida. La reproducción usa `reused_recorded_at`, así que `Workflow::now()` después de un paso reutilizado coincide con la hora de la ejecución fallida. Después de una llamada reutilizada a un workflow hijo, es la hora en que el hijo terminó por primera vez. Un paso reutilizado por un segundo redrive conserva la hora en que se ejecutó por primera vez. ### Solicitar un redrive {#request-a-redrive} @@ -183,11 +184,12 @@ El redrive acepta una ejecución fallida cuando se cumple todo lo siguiente: - La ejecución es la ejecución actual de la instancia. - La ejecución falló porque un fallo de actividad llegó al código del workflow y no se capturó, o porque el código del workflow lanzó una excepción o un límite estructural la detuvo. Se rechaza una ejecución que falló por un tiempo límite del workflow. -- Cada paso anterior al paso fallido es una actividad completada, un efecto secundario, un marcador de versión, un `timer()` que se disparó, un upsert de memo o de atributo de búsqueda, una espera de señal que recibió y aplicó su señal, o un update que se aceptó, se aplicó y se completó con los mismos argumentos. Un update rechazado, y uno que el fallo cerró antes de ejecutarse, se permiten y se omiten. Los payloads de actividades, efectos secundarios, señales y updates deben guardarse en línea. Un payload en el almacenamiento externo de payloads se rechaza. +- Cada paso anterior al paso fallido es una actividad completada, un efecto secundario, un marcador de versión, un `timer()` que se disparó, un upsert de memo o de atributo de búsqueda, una espera de señal que recibió y aplicó su señal, un update que se aceptó, se aplicó y se completó con los mismos argumentos o, en Workflow 2.26 y versiones posteriores, una llamada a un workflow hijo que se completó. Un update rechazado, y uno que el fallo cerró antes de ejecutarse, se permiten y se omiten. Los payloads de actividades, efectos secundarios, señales, updates y resultados de hijos deben guardarse en línea. Un payload en el almacenamiento externo de payloads se rechaza. - La definición del workflow coincide con la huella registrada al iniciar la ejecución, o pasaste `allow_definition_change` y el código corregido reproduce los pasos completados. Se rechaza un fallo del código del workflow sobre la misma definición. - El plazo de ejecución no ha vencido. -- La ejecución no tiene workflow padre, ni workflows hijos, ni actividades locales, y su entrada está almacenada en línea. -- Si un worker de servicio inició la ejecución, los pasos anteriores al fallo son solo actividades, efectos secundarios, marcadores de versión y temporizadores disparados. Los upserts de memo y de atributo de búsqueda, las esperas de señal y los updates aplicados se rechazan en ejecuciones de servicio. +- La ejecución no tiene workflow padre ni actividades locales, y su entrada está almacenada en línea. Antes de Workflow 2.26, tampoco tiene workflows hijos. Una ejecución que es a su vez un hijo nunca recibe un redrive, porque su padre ya registró el resultado del hijo. +- Cada llamada a un workflow hijo anterior al paso fallido se completó por sí sola, fuera de un grupo paralelo o de un ámbito de cancelación, sin reintento ni continuar como nueva ejecución. +- Si un worker de servicio inició la ejecución, los pasos anteriores al fallo son solo actividades, efectos secundarios, marcadores de versión y temporizadores disparados. Los upserts de memo y de atributo de búsqueda, las esperas de señal, los updates aplicados y las llamadas completadas a workflows hijos se rechazan en ejecuciones de servicio. Un rechazo indica la primera regla que no se cumplió: @@ -197,7 +199,12 @@ Un rechazo indica la primera regla que no se cumplió: | `source_run_not_current` | Existe una ejecución más reciente de la instancia. | | `unrecorded_failure_boundary` | El fallo de la ejecución no tiene un paso registrado, como un fallo del código del workflow registrado por una versión anterior a 2.19.0. | | `workflow_code_failure_requires_corrected_definition` | El código del workflow lanzó una excepción y la definición no ha cambiado, así que el mismo código volvería a lanzarla. | -| `unsupported_history` | El historial anterior al fallo contiene un paso que redrive no puede reutilizar, como un workflow hijo o un temporizador cancelado. | +| `unsupported_history` | El historial anterior al fallo contiene un paso que redrive no puede reutilizar, como un temporizador cancelado. Antes de Workflow 2.26, cualquier workflow hijo. | +| `unsupported_open_child` | Una llamada a un workflow hijo anterior al fallo nunca se cerró. Workflow 2.26 y versiones posteriores. | +| `unsupported_child_outcome` | Un workflow hijo anterior al fallo falló, se canceló o se terminó. Workflow 2.26 y versiones posteriores. | +| `unsupported_child_workflow` | Una llamada a un workflow hijo está en un grupo paralelo o en un ámbito de cancelación, se reintentó o continuó como nueva ejecución, o sus eventos no indican una única llamada hija. Workflow 2.26 y versiones posteriores. | +| `external_child_result_not_supported` | El resultado de un workflow hijo completado está en el almacenamiento externo de payloads. Workflow 2.26 y versiones posteriores. | +| `unavailable_child_result` | El resultado de un workflow hijo completado no se puede decodificar. Workflow 2.26 y versiones posteriores. | | `unsupported_local_activity` | El historial contiene una actividad local. | | `unsupported_timer` | El historial contiene un tiempo límite de condición o de señal, un temporizador de limpieza tras cancelación, o un temporizador dentro de un ámbito de cancelación o de un grupo paralelo. | | `incomplete_timer_step` | A un paso de temporizador le falta el evento de programación o el de disparo. | @@ -224,7 +231,7 @@ Un rechazo indica la primera regla que no se cumplió: | `definition_incompatible_with_prefix` | El código corregido no puede reproducir los pasos completados. `definition_mismatch` indica el primer paso que difiere. | | `definition_check_over_budget` | El historial completado supera el presupuesto de historial que permite la comprobación de reproducción. | | `definition_change_requires_replay_check` | Un worker de servicio inició la ejecución, así que el redrive no puede comprobar una definición cambiada. | -| `service_redrive_history_not_qualified` | Un worker de servicio inició la ejecución, y los pasos anteriores al fallo incluyen un upsert de memo, un upsert de atributo de búsqueda, una espera de señal o un update aplicado. Redrive rechaza estos pasos en ejecuciones de servicio hasta que pueda comprobar, para cada runtime de SDK, si puede reproducirlos en replay. | +| `service_redrive_history_not_qualified` | Un worker de servicio inició la ejecución, y los pasos anteriores al fallo incluyen un upsert de memo, un upsert de atributo de búsqueda, una espera de señal, un update aplicado o una llamada completada a un workflow hijo. Redrive rechaza estos pasos en ejecuciones de servicio hasta que pueda comprobar, para cada runtime de SDK, si puede reproducirlos en replay. | | `request_id_already_used` | El `request_id` ya se usó para otro redrive de la instancia. | | `already_redriven` | Lo informan el detalle de la ejecución y `describe()` para una ejecución que ya recibió un redrive. Una solicitud de redrive para ella devuelve en su lugar el sucesor existente. | | `invalid_request_id` | El `request_id` tiene más de 191 caracteres. | @@ -246,6 +253,8 @@ En Workflow 2.20.0 y posteriores, el detalle de la ejecución y `describe()` inf ### Versiones anteriores y el Server nativo {#redrive-earlier-releases} +Las versiones de Workflow anteriores a 2.26.0 rechazan cualquier workflow hijo del historial con `unsupported_history`. Ignoran `reused_recorded_at` en los eventos de workflows hijos, así que una sucesora de 2.26.0 que reutilizó una llamada hija puede reproducirse allí con una hora del workflow distinta, y plazos distintos, después de la llamada. También rechazan volver a hacerle un redrive. Una vez que exista una sucesora así, mantenga los workers en 2.26.0 o posterior, o confirme que ningún historial así puede reproducirse, antes de volver atrás. + Workflow 2.20.0 no rechaza nada que 2.20.1 acepte. En 2.20.0, `outbox()->sendReference()` en el código de workflow reutilizado vuelve a enviar, y un `inbox()->receive()` en replay puede devolver otros mensajes o ninguno, o consumir un mensaje más nuevo ([workflow#1010](https://github.com/durable-workflow/workflow/issues/1010)). Workflow 2.19.0 rechaza un update aplicado (`unsupported_history`). También rechaza el redrive de un sucesor que reutilizó un update (`unsupported_history`) o una espera de señal (`mismatched_signal_receipt`). El detalle de la ejecución y `describe()` muestran los vínculos de redrive como respaldo de diagnóstico. diff --git a/i18n/es/docusaurus-plugin-content-docs/current/features/child-workflows.md b/i18n/es/docusaurus-plugin-content-docs/current/features/child-workflows.md index 77708aa4a3b..0e7261a6f3a 100644 --- a/i18n/es/docusaurus-plugin-content-docs/current/features/child-workflows.md +++ b/i18n/es/docusaurus-plugin-content-docs/current/features/child-workflows.md @@ -200,7 +200,7 @@ $results = all([ - Al cerrar el padre por cualquier motivo, el motor consulta enlaces abiertos cuya política no sea abandonar y envía a cada hijo el comando correspondiente (solicitud cooperativa, cancelación o terminación). - Si el hijo ya se cerró, se omite silenciosamente el comando. - La aplicación es de mejor esfuerzo: rechazar un comando del hijo (por ejemplo, ya terminal) no afecta al cierre padre. El éxito registra `ParentClosePolicyApplied` en el padre; el fallo registra `ParentClosePolicyFailed` para distinguir ambos resultados. -- Continuar como nueva ejecución **no** activa la política, porque la instancia sigue activa bajo otra ejecución. +- Continuar como nueva ejecución **no** activa la política, porque la instancia sigue activa bajo otra ejecución. Desde Workflow 2.26, la aplica en su lugar la ejecución final de la cadena. Consulta [Continuar como nueva ejecución e hijos abiertos](#continue-as-new-and-open-children). ### Matriz de disposiciones del padre {#parent-disposition-matrix} @@ -213,9 +213,21 @@ La política actúa en toda disposición terminal del padre, pero no en ejecucio | Plazo vencido | Sí | Tras `WorkflowTimedOut` en cierres por plazo de ejecución o plazo global del workflow. | | Cancelado | Sí | Después de que el comando aceptado `CancelRequested` cierre al padre. | | Terminado | Sí | Después de que el comando aceptado `TerminateRequested` cierre al padre. | -| Continuar como nueva ejecución | No | La instancia sigue activa en la nueva ejecución; los enlaces hijos se redirigen conservando su política. | +| Continuar como nueva ejecución | No | La instancia sigue activa en la nueva ejecución. Desde Workflow 2.26, la ejecución continuada asume la supervisión de los hijos abiertos, y la ejecución final de la cadena aplica su política. | | Restablecer | No aplicable actualmente | El runtime v2 no expone un comando independiente ni disposición terminal de restablecimiento. Una futura operación de restablecimiento o reparación que cierre o sustituya al padre debe definir si transfiere la propiedad de los hijos; si la anterior queda terminal, debe aplicar la política antes de dejar de poseer hijos abiertos. | +### Continuar como nueva ejecución e hijos abiertos {#continue-as-new-and-open-children} + +En Workflow 2.26 y versiones posteriores, un padre que continúa como nueva ejecución mientras los hijos que inició siguen abiertos los entrega a la ejecución continuada, en la misma transacción. Las ejecuciones en modo embebido y en modo servicio se comportan igual: + +- Cada hijo abierto obtiene una fila en la tabla `workflow_child_supervisions`, que crea la migración de 2.26. Un hijo que ya se cerró no se entrega. +- El enlace hijo, la llamada hija, la secuencia, los plazos y la política de cierre del padre quedan como los registró la ejecución que los inició. Cuando la ejecución continuada vuelve a continuar como nueva ejecución, vuelve a entregar los hijos. +- Cuando la ejecución final de la cadena se completa, falla, vence su plazo, se cancela o se termina, aplica la política de cada hijo y registra `ParentClosePolicyApplied` o `ParentClosePolicyFailed` en su propio historial. `abandon` sigue siendo `abandon`. La ejecución anterior ya cerrada no recibe historial nuevo. +- La ejecución continuada no tiene referencia a estos hijos, y sus resultados no se le entregan. Pasa lo que necesite la siguiente ejecución en los argumentos de `continueAsNew()`. +- Un hijo entregado que falla se reintenta con la política de reintentos que registró la ejecución que lo inició, con la misma identidad de llamada hija y el mismo recuento de intentos, mientras una ejecución de la cadena siga supervisándolo. El `WorkflowStarted` de la ejecución de reintento indica como padre la ejecución que lo inició, y la ejecución final de la cadena aplica la política de cierre del padre a la ejecución de reintento. El fallo es definitivo cuando se agotan los intentos, el fallo no admite reintentos o la cadena se ha cerrado. + +Antes de 2.26, estos hijos seguían ejecutándose después de cerrarse la cadena y su política nunca se aplicaba, y un hijo que fallaba después de que su padre continuara como nueva ejecución no se reintentaba. Consulta las [notas de versión de 2.26.0](https://github.com/durable-workflow/workflow/releases/tag/2.26.0). + ### Cuándo usar cada política {#when-to-use-each-policy} **Abandonar** (predeterminada) es adecuada si el hijo representa trabajo independiente que debe completarse con independencia del padre, como una notificación o limpieza obligatoria. diff --git a/i18n/es/docusaurus-plugin-content-docs/current/features/continue-as-new.md b/i18n/es/docusaurus-plugin-content-docs/current/features/continue-as-new.md index 08a4623ec51..47d8cbb6d1a 100644 --- a/i18n/es/docusaurus-plugin-content-docs/current/features/continue-as-new.md +++ b/i18n/es/docusaurus-plugin-content-docs/current/features/continue-as-new.md @@ -70,6 +70,10 @@ Los bucles prolongados pueden desprenderse del historial sin inventar otro id p El código puede observar la longitud actual del historial y una sugerencia de continuación mediante contexto explícito del runtime. Así puede traspasar deliberadamente antes de alcanzar límites costosos. +En Workflow 2.26 y versiones posteriores, usa `shouldContinueAsNewAtStep()` y `historyBudgetAtStep()`. Solo cuentan el historial registrado antes del paso actual del workflow, así que la misma línea devuelve la misma respuesta en cada replay. Un bucle que comprueba el presupuesto en cada iteración continúa como nueva ejecución una sola vez, en la primera iteración que supera el umbral. + +Los métodos anteriores leen todo el historial actual. Dentro de un bucle, una iteración anterior puede ver en el replay un total posterior y tomar una rama distinta de la que tomó la primera vez. No han cambiado, así que las ejecuciones que ya decidieron con ellos siguen reproduciéndose. + ```php use function Workflow\V2\activity; use function Workflow\V2\continueAsNew; @@ -97,6 +101,8 @@ class PollingWorkflow extends Workflow | `$this->historyLength()` | `int` | Número de eventos de historial de la ejecución actual | | `$this->historySize()` | `int` | Tamaño total de los eventos en bytes | | `$this->shouldContinueAsNew()` | `bool` | `true` cuando supera el presupuesto configurado de cantidad o bytes | +| `$this->historyBudgetAtStep()` | `array` | El presupuesto en el paso actual: `history_event_count`, `history_size_bytes`, `history_fan_out`, `continue_as_new_recommended`, `pressure`, `pressure_dimensions` y `observation` (`step_prefix.v1`). Workflow 2.26 y versiones posteriores. | +| `$this->shouldContinueAsNewAtStep()` | `bool` | `continue_as_new_recommended` de `historyBudgetAtStep()`. Úsalo en bucles. Workflow 2.26 y versiones posteriores. | ### Configuración {#configuration} @@ -112,7 +118,7 @@ Los umbrales de recomendación son configurables: ], ``` -`shouldContinueAsNew()` devuelve `true` al superar cualquiera. Los resúmenes también registran `history_event_count`, `history_size_bytes` y `continue_as_new_recommended` para que Waterline señale ejecuciones largas en las vistas de flota. +`shouldContinueAsNew()` y `shouldContinueAsNewAtStep()` devuelven `true` al superar cualquiera. Los resúmenes también registran `history_event_count`, `history_size_bytes` y `continue_as_new_recommended` para que Waterline señale ejecuciones largas en las vistas de flota. ## Conservación de metadatos {#metadata-carry-forward} @@ -152,4 +158,6 @@ class PollingWorkflow extends Workflow } ``` +Un padre que continúa como nueva ejecución mientras los workflows hijos que inició siguen abiertos los entrega a la ejecución continuada. Consulta [Continuar como nueva ejecución e hijos abiertos](./child-workflows.md#continue-as-new-and-open-children). + Para bucles prolongados de intervención humana o asistentes, prefiere la fachada de primera clase `$this->inbox()` / `$this->outbox()` de [Flujos de mensajes](./message-streams.md). Los mensajes pendientes del flujo y el cursor pasan a la nueva ejecución; los mensajes consumidos permanecen en la original como evidencia histórica. Workflow 2.20.1 y versiones anteriores dejaban los mensajes pendientes del flujo en la ejecución cerrada ([workflow#1018](https://github.com/durable-workflow/workflow/issues/1018), corregido en 2.20.2); consulta [Flujos de mensajes](./message-streams.md#continue-as-new). diff --git a/i18n/es/docusaurus-plugin-content-docs/current/features/search-attributes.md b/i18n/es/docusaurus-plugin-content-docs/current/features/search-attributes.md index e5b54859106..d18d2b5ba04 100644 --- a/i18n/es/docusaurus-plugin-content-docs/current/features/search-attributes.md +++ b/i18n/es/docusaurus-plugin-content-docs/current/features/search-attributes.md @@ -105,7 +105,7 @@ En el Server puede registrar un atributo de búsqueda con un tipo mediante `POST El registro solo restringe las claves que registra. Desde Server nativo 3.5.0, una clave no registrada se sigue aceptando y su tipo se infiere, como en un namespace sin atributos registrados. Registrar un atributo no rompe los workflows en ejecución que hacen upsert de otras claves. PHP Server 2.x y Server nativo anterior a 3.5.0 rechazan toda clave no registrada en cuanto se registra cualquier atributo, así que ahí registre todas las claves que usan sus workflows antes de registrar la primera. -Eliminar un registro deja de validar esa clave. Los valores almacenados y los workflows en ejecución no cambian, y los upserts posteriores de la clave vuelven a inferirse. +Eliminar un registro deja de validar esa clave. Los valores almacenados y los workflows en ejecución no cambian, y los upserts posteriores de la clave vuelven a inferirse. En el Server nativo, una consulta de lista que filtra por una clave no registrada, incluida una cuyo registro eliminó, se rechaza porque la clave no está definida en el namespace. Para cambiar el tipo de un atributo, registre un nombre de atributo nuevo con el tipo nuevo, actualice sus workflows para que lo escriban y filtre por el nombre nuevo cuando las ejecuciones existentes se hayan puesto al día. Si elimina y vuelve a registrar el mismo nombre con otro tipo, los valores anteriores quedan en el tipo antiguo. diff --git a/i18n/es/docusaurus-plugin-content-docs/current/polyglot/php.md b/i18n/es/docusaurus-plugin-content-docs/current/polyglot/php.md index f1f86d2d89e..d7ba8bedb50 100644 --- a/i18n/es/docusaurus-plugin-content-docs/current/polyglot/php.md +++ b/i18n/es/docusaurus-plugin-content-docs/current/polyglot/php.md @@ -303,7 +303,7 @@ Novedades de estas versiones: - **Sufijos de historial sticky (3.14).** Los workers anuncian `sticky_history_suffix`. En Server 3.5.0 o posterior, un worker que ya tiene el historial de una ejecución recibe solo los eventos posteriores a la secuencia que guardó en caché. Un sufijo que no continúa exactamente el historial en caché se descarta y se obtiene el historial completo. Los Servers anteriores siguen enviando el historial completo. - **Origen del schedule (3.13).** `WorkflowContext::scheduleOrigin()` devuelve el id del schedule, la hora de ocurrencia y el número de disparo que iniciaron la ejecución, o `null` en un inicio normal. El valor es el mismo en el replay. Desde Server 3.5.0, una ejecución que continúa como nueva conserva su origen de schedule. -- **Continuaciones de actividad (3.12).** Pase `enableActivityContinuation: true` al constructor de `Worker` para enviar los siguientes comandos del workflow junto con un resultado de actividad correcto cuando el Server anuncia `activity_workflow_continuation` (Server native 3.4.0 o posterior). El valor predeterminado es `false`. Use 3.12.1 o posterior si lo activa, y vacíe o desactive esos workers antes de bajar de versión el Server o añadir nodos de Server anteriores. +- **Continuaciones de actividad (3.12).** Pase `enableActivityContinuation: true` al constructor de `Worker` para enviar los siguientes comandos del workflow junto con un resultado de actividad correcto cuando el Server anuncia `activity_workflow_continuation` (Server native 3.4.0 o posterior). El valor predeterminado es `false`. Activarlo cuesta actualmente rendimiento: en nuestro benchmark bajo carga, los workflows fueron un 24–49% más lentos con la opción activada y usaron el doble de transacciones de base de datos ([medición](https://github.com/durable-workflow/server/issues/1078)). Use 3.12.1 o posterior si lo activa, y vacíe o desactive esos workers antes de bajar de versión el Server o añadir nodos de Server anteriores. Consulte el [registro de cambios de 3.14.0](https://github.com/durable-workflow/sdk-php/blob/3.14.0/CHANGELOG.md) para ver la lista completa. diff --git a/i18n/es/docusaurus-plugin-content-docs/current/testing.md b/i18n/es/docusaurus-plugin-content-docs/current/testing.md index a7b3400261f..ebd0cad3410 100644 --- a/i18n/es/docusaurus-plugin-content-docs/current/testing.md +++ b/i18n/es/docusaurus-plugin-content-docs/current/testing.md @@ -359,7 +359,7 @@ Ambas políticas registran comandos duraderos y eventos de historial. También p ### Probar el presupuesto del historial {#testing-history-budget} -Los campos de `HistoryBudget` (`history_event_count`, `history_size_bytes`, `continue_as_new_recommended`) aparecen en la proyección del resumen de ejecución y están disponibles mediante `RunDetailView`. En el workflow, la clase base `Workflow` los expone como `$this->historyLength()`, `$this->historySize()` y `$this->shouldContinueAsNew()`: +Los campos de `HistoryBudget` (`history_event_count`, `history_size_bytes`, `continue_as_new_recommended`) aparecen en la proyección del resumen de ejecución y están disponibles mediante `RunDetailView`. En el workflow, la clase base `Workflow` los expone como `$this->historyLength()`, `$this->historySize()` y `$this->shouldContinueAsNew()`. Dentro de un bucle, usa `$this->shouldContinueAsNewAtStep()` (Workflow 2.26 y versiones posteriores), que da la misma respuesta en cada replay: ```php use Workflow\V2\Workflow; @@ -371,7 +371,7 @@ final class LongRunningWorkflow extends Workflow while (true) { // ... process work ... - if ($this->shouldContinueAsNew()) { + if ($this->shouldContinueAsNewAtStep()) { Workflow::continueAsNew($this->carryForwardState()); } } diff --git a/i18n/es/source-hashes.json b/i18n/es/source-hashes.json index aaa9e3d33f5..29802b30c7c 100644 --- a/i18n/es/source-hashes.json +++ b/i18n/es/source-hashes.json @@ -4,7 +4,7 @@ "ai-agent-workflow-engine.md": "28016466b179adbabdff6467ce351100c9bee48529a8bec9df7ec22c8d786d4d", "ai-assisted-development.md": "b246bb60585fb7a69bc534978f470f3f16e899e1f8f203ba0847d2d11b8a1ec3", "capabilities.md": "d9a2bbc0d04adf8cb3f4c7f42d779a43aafab60791210305e7e476c0499528fc", - "compatibility.md": "567310faf420fbd5229c5eef69721e8b7d09f033333cbaec21b72acaf81b6690", + "compatibility.md": "ad5c8519be03ae1e7b6e5e03b05a886862fd67c603b241ecb5baf2be5cd59610", "configuration/customization-matrix.md": "3d115863eaee7852b541bcd01615f424cc19c5847c7cd7d75e5ae63bc3f5cc78", "configuration/database-connection.md": "cc83ae77133236309506fa44d39bfd0c939c32a6154c0bd6099bc64c83bdaec9", "configuration/ensuring-same-server.md": "6c665f37cc198c7b1a775a60a94aab5ff4e55383385e76f1834c7840559b512a", @@ -24,18 +24,18 @@ "defining-workflows/activities.md": "05b46f73477a0bbd5f21d17ac37def8a8eac53f1e629155805c98cc46e75b418", "defining-workflows/passing-data.md": "c5d36126b0b15f1780119f6418e8bbe5a63e03353be5a0bb69385206ef0ad635", "defining-workflows/starting-workflows.md": "722b80454b577b0715ff50db70c7cda2cd02c34c505dd1219a83307852d325a4", - "defining-workflows/workflow-api.md": "a6150e75302323b49f350159ce3568a51a19701bb81829915615f754592ee79c", + "defining-workflows/workflow-api.md": "3c13894c1fdbe77bb1379c62bbdb0ef213c81f1cba5b477d45402dcc7fe87237", "defining-workflows/workflow-id.md": "ca3b43253a748b27dca1af9f82fcf8c4c133e14f13e1b82eaa1ca2ed0996d4bf", "defining-workflows/workflow-status.md": "8e8cb27ff44c890d489d89bf166375acfdfaecabd990a2235e106fab1592d529", "defining-workflows/workflows.md": "f467bc73de32aa5d722c61ce085065460382ae7dd44cea4625847d9fcdc4c97c", "deployment.md": "6aa439b1ebfdc2affccaf6fe6fff7519776a4ffcad8d3cb5956b665e7c97257f", - "failures-and-recovery.md": "598b538e2bcb6a40a4f2d4c0c462705bab30ef96767144f6590c2cc93b68a98a", + "failures-and-recovery.md": "4209521a8783939d458658a7afea64124c34571080c97feb2868a273db88db3e", "features/activity-execution-model.md": "e8c37520ae46a7efb30438f4fc06bf893c1df430cb1f92c48963697adaf09082", "features/cancel-and-terminate.md": "cedd1e6c51dfa551e00edc1d39739ff1f67d558d2a0be92143f478cb6111536b", - "features/child-workflows.md": "57016591fb8816aed7b077e204f1c80f9c6a8dff7501bc00a141c41a4607306b", + "features/child-workflows.md": "278b634b8b48b94203309cdba27d6116897a2919cab19628add8cd85dadb08d3", "features/concurrency.md": "a7a3eb2274f7b14faf722494569b7663c07ab48afdf2e9225e58914b84cacbb4", "features/condition-waits.md": "451261eda990c9591a0db69839d872184b5c64da6b537a582133095b8d4b599e", - "features/continue-as-new.md": "50c79f317155e052a3f2f37d198a71bdfc496a454905293f40cf09d73138f25b", + "features/continue-as-new.md": "a5309192c685abeb5295071d423824ae2287e68d247a6661f18d3ab21f9bdc9c", "features/events.md": "c466df05908748489226a3d1410c9203cf6f2986a4bb7539db1c5f82715abc7b", "features/external-payload-storage.md": "acc312fa2f50a43c96e1d235439124d28a7048f0bf3abac34319467fcbf7e898", "features/heartbeats.md": "4fce9636d68c89f29f259d52e463cd67eccf0bc55ad4d53338ed03329892b365", @@ -45,7 +45,7 @@ "features/queries.md": "c66dd9542a062edd8158a46cebc9f1bf926aaf3599dca4a3122bd9860df6e2a2", "features/sagas.md": "046ba5661ccb5ac71a236356d243b021d9830123e3798afce491118434e83820", "features/schedules.md": "40d30b2767e7ed043e2b0c7180915c256accea3e7a3401c38d1bf75bfe1c2213", - "features/search-attributes.md": "567d89858cd82e86672b210154001a272b17a5f87e13dbfa7de1b8e093d615b8", + "features/search-attributes.md": "bb66d83f64e0098354d86ac237e6867b9819098044101ba9a60a6a00a3961dd1", "features/service-operations.md": "912131c0a8ef393040a933fb4a66e68abcb9d475a3ebd47c85287d4032f45a0e", "features/side-effects.md": "abdccab8d6fc1a12b3eff8a4ccc58730ac36f523559b4ad89c5c2a8d201a3b86", "features/signal+timer.md": "a05fc480544fa71f6c9b215ad3417f71b8475dd81f9de8ee18d7a3b69ac33a23", @@ -80,7 +80,7 @@ "polyglot/invocable-carrier.md": "d32d8b5c7c33204b342f977e0af734166d91e96073db1a49ccb4d414a6d67380", "polyglot/invocable-php-handler.md": "3b678eb1d69fe32dfcfdc05d36b33e49e01b79d7216bd784f6a61a6f1c3c3a13", "polyglot/namespace-auth-workers.md": "2b4078ceb74b849f12cb1975b410ff8e7266cd4345f6cf1d4dd906db12460ffb", - "polyglot/php.md": "04f7eeebf842bbcd2f278f96ee21fbbf4f97d424a27e717d65e1c73273bce095", + "polyglot/php.md": "309e83622754b9d9abc65807280f2dab175a009054a001456ef1316776f11101", "polyglot/polling-patterns.md": "30875099a23731c6c471b481a771378acc6ff57eed2fda4405a509057534c989", "polyglot/portable-worker-affinity.md": "40973c6a31a76845b4f95e9a505e68ad76abd5174bbdccf37993cdebc8904959", "polyglot/prerelease-history-migration.md": "a57f05f492228a8a67791f9152648a1e5f80856325b78777cf63b6ef49b7413c", @@ -105,6 +105,6 @@ "sdk-neutrality.md": "7b0714c123ade4904591870fc20e9a797da1e5485b2a6c87ca3eaa00c5de6ed6", "sponsors.md": "e85e14375743ca8fa50e3a48f894b160e28272573aa88480064f74010ebee98a", "support.md": "706807b3902599dda6080f632ec1f893017ea18bbe9585f533dcdbd6d85f4621", - "testing.md": "250bc7dfd46f99eaeb392b329947813b064bda72026645198e3aefc80043a813", + "testing.md": "176abf226936c7711c2df523fb8a94e92fcf62e6f804d99f2e32b9135f626547", "waterline-operator-api.md": "2aca03b2c14100060b40be0bb033a82525ba924908834e9060ec746ead26f36d" } diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/compatibility.md b/i18n/fr/docusaurus-plugin-content-docs/current/compatibility.md index d5e9b7a3e03..cc538f0fd87 100644 --- a/i18n/fr/docusaurus-plugin-content-docs/current/compatibility.md +++ b/i18n/fr/docusaurus-plugin-content-docs/current/compatibility.md @@ -96,12 +96,12 @@ embarqué et le SDK en mode service ont des contrats distincts. | Branche du paquet | PHP | Laravel | | --- | --- | --- | -| Workflow embarqué 2.24 actuel | PHP 8.2+ en 8.x ; PHP 8.3+ pour Laravel 13 | `^12.69.0` ou `^13.30.0` | +| Workflow embarqué 2.26 actuel | PHP 8.2+ en 8.x ; PHP 8.3+ pour Laravel 13 | `^12.69.0` ou `^13.30.0` | | Workflow embarqué 2.20.5 | PHP `^8.1`, sous réserve du minimum du framework | `^10.50.4`, `^11.56.1`, `^12.69.0` ou `^13.30.0` | | SDK PHP 3.14 publié | SDK de base PHP `^8.1` ; le pont Laravel exige PHP `^8.2`, et PHP 8.3+ pour Laravel 13 | `^12.69.0` ou `^13.30.0` | | SDK PHP 3.9.5 | SDK de base PHP `^8.1` ; le pont Laravel suit aussi le minimum du framework | `^10.50.4`, `^11.56.1`, `^12.69.0` ou `^13.30.0` | -Le [contrat embarqué publié](https://github.com/durable-workflow/workflow/blob/2.24.0/resources/laravel-embedded-upgrade-contract.json) +Le [contrat embarqué publié](https://github.com/durable-workflow/workflow/blob/2.26.0/resources/laravel-embedded-upgrade-contract.json) et le `composer.json` de chaque version font autorité. La version embarquée actuelle a été vérifiée sur Laravel 12/PHP 8.2–8.4 et Laravel 13/PHP 8.3–8.4. Elle retire PHP 8.1 et Laravel 10/11. Le [guide historique v1 stable](/docs/1.x/installation/) @@ -143,6 +143,16 @@ Workflow 2.23 et 2.24 conservent les planchers de support de 2.21 et le protocol Voir les notes de version de [2.23.0](https://github.com/durable-workflow/workflow/releases/tag/2.23.0), [2.23.1](https://github.com/durable-workflow/workflow/releases/tag/2.23.1), [2.23.2](https://github.com/durable-workflow/workflow/releases/tag/2.23.2) et [2.24.0](https://github.com/durable-workflow/workflow/releases/tag/2.24.0). +Workflow 2.25 et 2.26 conservent les planchers de support de 2.21 et le protocole de worker embarqué `1.22`. 2.25 n'ajoute aucune migration de base de données. 2.26 en ajoute une : exécutez donc `php artisan migrate` lors de la mise à niveau. Elle crée la table `workflow_child_supervisions`. Changements à vérifier avant la mise à niveau : + +- Depuis 2.26, un parent qui continue dans une nouvelle exécution alors que des enfants qu'il a démarrés sont encore ouverts les transmet à l'exécution suivante. La dernière exécution de la chaîne leur applique leur politique de clôture du parent, et un enfant qui échoue est toujours relancé selon la politique de nouvelles tentatives enregistrée. Voir [Continuation et enfants ouverts](./features/child-workflows.md#continue-as-new-and-open-children). +- Depuis 2.26, les migrations des versions antérieures qui remplissent les lignes existantes (`2026_07_13`, `2026_09_24`, `2026_09_29` et `2026_10_11`) ne verrouillent plus la table pendant tout le remplissage. Elles ajoutent d'abord la colonne, remplissent les lignes par petits lots, puis construisent leurs index sans bloquer les écritures. Si l'une d'elles est interrompue, exécutez de nouveau `php artisan migrate`. Les installations qui les ont déjà exécutées ne sont pas concernées. +- Depuis 2.26, le redrive réutilise un workflow enfant terminé avant l'échec. Les versions antérieures à 2.26 rejouent un tel successeur avec un temps de workflow différent après l'enfant réutilisé : gardez donc les workers en 2.26 ou plus dès qu'un tel successeur existe. Voir [Relancer une exécution échouée par redrive](./failures-and-recovery.md#redrive). +- Depuis 2.26, `historyBudgetAtStep()` et `shouldContinueAsNewAtStep()` lisent le budget d'historique de la même façon à chaque relecture. Utilisez-les dans les boucles. Voir [Budget d'historique](./features/continue-as-new.md#history-budget). +- Depuis 2.25, dépasser une limite fixe de mémo ou d'attributs de recherche lève `StructuralLimitExceededException` au lieu de `InvalidArgumentException`, et la valeur par défaut de `memo_size_bytes` est 65 536. Voir [Limites structurelles](./constraints/structural-limits.md). + +Voir les notes de version de [2.25.0](https://github.com/durable-workflow/workflow/releases/tag/2.25.0) et [2.26.0](https://github.com/durable-workflow/workflow/releases/tag/2.26.0). + ## Niveaux de stabilité {#stability-levels} Chaque interface publique Durable Workflow porte exactement un de ces niveaux. diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/defining-workflows/workflow-api.md b/i18n/fr/docusaurus-plugin-content-docs/current/defining-workflows/workflow-api.md index 03c4bde85a9..f02eeb2974e 100644 --- a/i18n/fr/docusaurus-plugin-content-docs/current/defining-workflows/workflow-api.md +++ b/i18n/fr/docusaurus-plugin-content-docs/current/defining-workflows/workflow-api.md @@ -46,6 +46,8 @@ abstract class Workflow public function historyLength(): int; public function historySize(): int; public function shouldContinueAsNew(): bool; + public function historyBudgetAtStep(): array; + public function shouldContinueAsNewAtStep(): bool; } ``` @@ -58,6 +60,8 @@ abstract class Workflow | `historyLength()` | Le workflow a besoin d’un indicateur de budget d’historique basé sur le nombre d’événements. | Nombre actuel d’événements d’historique. | | `historySize()` | Le workflow a besoin d’un indicateur de budget d’historique en octets. | Taille approximative de l’historique persistant en octets. | | `shouldContinueAsNew()` | Le workflow doit passer à une nouvelle exécution avant que l’historique devienne coûteux. | `true` lorsque les budgets d’historique configurés recommandent une rotation. | +| `historyBudgetAtStep()` | Le workflow lit le budget plusieurs fois dans une exécution, par exemple dans une boucle (Workflow 2.26+). | Compteurs du budget à l’étape courante, identiques à chaque relecture. | +| `shouldContinueAsNewAtStep()` | Une boucle décide s’il faut passer à une nouvelle exécution (Workflow 2.26+). | `true` lorsque l’historique avant l’étape courante dépasse un budget configuré. | ## Commandes durables {#durable-commands} diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/failures-and-recovery.md b/i18n/fr/docusaurus-plugin-content-docs/current/failures-and-recovery.md index fb0b735f545..51d60bc7ec4 100644 --- a/i18n/fr/docusaurus-plugin-content-docs/current/failures-and-recovery.md +++ b/i18n/fr/docusaurus-plugin-content-docs/current/failures-and-recovery.md @@ -122,6 +122,7 @@ Le successeur rejoue le code du workflow depuis le début : - Un mémo ou un attribut de recherche sur lequel le code du workflow a fait un upsert avant l’étape échouée est réutilisé dans l’ordre des étapes, et le successeur garde les mêmes valeurs. - Une attente de signal (`await('name')`) qui a reçu et appliqué son signal est réutilisée avec la valeur du signal. Le signal n’est pas remis à nouveau. - Un update accepté, appliqué et terminé avant l’étape échouée est enregistré de nouveau à la même position. Le replay exécute le handler de l’update avec ses arguments enregistrés, si bien que l’état du workflow correspond. L’update n’est pas livré de nouveau. Un update rejeté, et un update que l’échec a fermé avant son exécution, sont laissés de côté. +- Dans Workflow 2.26 et les versions ultérieures, un appel de workflow enfant terminé avant l’étape échouée renvoie son résultat enregistré. L’enfant n’est pas redémarré. Le successeur enregistre les événements `ChildWorkflowScheduled`, `ChildRunStarted` et `ChildRunCompleted` de l’appel et conserve l’instance enfant, l’exécution enfant, l’identifiant de lien et l’identifiant d’appel d’origine, mais ne reçoit aucun lien enfant propre. - `outbox()->sendReference()` et `inbox()->receive()` dans le code de workflow réutilisé renvoient le message que l’exécution échouée a envoyé ou consommé. Ils ne l’envoient ni ne le consomment de nouveau. Un receive rejoué dont l’appel d’origine n’a rien trouvé relit le stream. - Dans Workflow 2.20.2 et les versions ultérieures, les messages entrants du stream encore en attente sur l’exécution échouée passent au successeur. Workflow 2.20.1 et les versions antérieures les laissaient sur l’exécution échouée, si bien que le successeur ne les recevait jamais ([workflow#1013](https://github.com/durable-workflow/workflow/issues/1013)). - Si un échec d’activité a mis fin à l’exécution, l’appel d’activité échoué est planifié comme une nouvelle exécution d’activité, avec la politique de nouvelles tentatives du code du workflow. Ses tentatives repartent de zéro. @@ -131,7 +132,7 @@ Le successeur rejoue le code du workflow depuis le début : - Le successeur conserve l’échéance d’exécution de l’exécution échouée. Son délai d’exécution repart au moment du redrive. - Chaque étape réutilisée porte `reused_from_run_id` et `reused_recorded_at`. Sur un événement d’update ou de signal réutilisé, les deux vont toujours de pair. - Un successeur qui a réutilisé des étapes peut à son tour faire l’objet d’un redrive. Un payload de signal ou d’update réutilisé garde dans `workflow_run_id` l’exécution qui l’a enregistré en premier, `reused_from_run_id` désigne l’exécution d’où vient le redrive, et chaque étape réutilisée garde l’heure de sa première exécution, si bien qu’une chaîne de redrives réutilise chaque étape une seule fois. -- En mode embedded, `Workflow::now()` dans le successeur commence à l’heure de démarrage de l’exécution échouée. Le rejeu utilise `reused_recorded_at`, donc `Workflow::now()` après une étape réutilisée correspond à l’heure de l’exécution échouée. Une étape réutilisée par un second redrive garde l’heure de sa première exécution. +- En mode embedded, `Workflow::now()` dans le successeur commence à l’heure de démarrage de l’exécution échouée. Le rejeu utilise `reused_recorded_at`, donc `Workflow::now()` après une étape réutilisée correspond à l’heure de l’exécution échouée. Après un appel de workflow enfant réutilisé, c’est l’heure à laquelle l’enfant s’est terminé la première fois. Une étape réutilisée par un second redrive garde l’heure de sa première exécution. ### Demander un redrive {#request-a-redrive} @@ -187,11 +188,12 @@ Le redrive accepte une exécution échouée lorsque toutes ces conditions sont r - L’exécution est l’exécution courante de l’instance. - L’exécution a échoué parce qu’un échec d’activité a atteint le code du workflow sans y être intercepté, ou parce que le code du workflow a levé une exception ou qu’une limite structurelle l’a arrêtée. Une exécution qui a échoué sur un délai du workflow est refusée. -- Chaque étape avant l’étape échouée est une activité terminée, un effet de bord, un marqueur de version, un `timer()` déclenché, un upsert de mémo ou d’attribut de recherche, une attente de signal qui a reçu et appliqué son signal, ou un update accepté, appliqué et terminé avec les mêmes arguments. Un update rejeté, et un update que l’échec a fermé avant son exécution, sont admis et laissés de côté. Les payloads d’activité, d’effet de bord, de signal et d’update doivent être stockés en ligne. Un payload placé dans le stockage externe des payloads est refusé. +- Chaque étape avant l’étape échouée est une activité terminée, un effet de bord, un marqueur de version, un `timer()` déclenché, un upsert de mémo ou d’attribut de recherche, une attente de signal qui a reçu et appliqué son signal, un update accepté, appliqué et terminé avec les mêmes arguments ou, dans Workflow 2.26 et les versions ultérieures, un appel de workflow enfant terminé. Un update rejeté, et un update que l’échec a fermé avant son exécution, sont admis et laissés de côté. Les payloads d’activité, d’effet de bord, de signal, d’update et de résultat d’enfant doivent être stockés en ligne. Un payload placé dans le stockage externe des payloads est refusé. - La définition du workflow correspond à l’empreinte enregistrée au démarrage de l’exécution, ou vous avez passé `allow_definition_change` et le code corrigé rejoue les étapes terminées. Un échec du code du workflow sur la même définition est refusé. - L’échéance d’exécution n’est pas dépassée. -- L’exécution n’a ni workflow parent, ni workflows enfants, ni activités locales, et son entrée est stockée en ligne. -- Si un worker de service a démarré l’exécution, les étapes avant l’échec sont uniquement des activités, des effets de bord, des marqueurs de version et des minuteurs déclenchés. Les upserts de mémo et d’attribut de recherche, les attentes de signal et les updates appliqués sont refusés pour les exécutions de service. +- L’exécution n’a ni workflow parent ni activités locales, et son entrée est stockée en ligne. Avant Workflow 2.26, elle n’a pas non plus de workflows enfants. Une exécution qui est elle-même un enfant ne fait jamais l’objet d’un redrive, car son parent a déjà enregistré le résultat de l’enfant. +- Chaque appel de workflow enfant avant l’étape échouée s’est terminé seul, hors d’un groupe parallèle ou d’une portée d’annulation, sans nouvelle tentative ni continue-as-new. +- Si un worker de service a démarré l’exécution, les étapes avant l’échec sont uniquement des activités, des effets de bord, des marqueurs de version et des minuteurs déclenchés. Les upserts de mémo et d’attribut de recherche, les attentes de signal, les updates appliqués et les appels de workflow enfant terminés sont refusés pour les exécutions de service. Un refus indique la première règle non respectée : @@ -201,7 +203,12 @@ Un refus indique la première règle non respectée : | `source_run_not_current` | Une exécution plus récente de l’instance existe. | | `unrecorded_failure_boundary` | L’échec de l’exécution n’a aucune étape enregistrée, par exemple un échec du code du workflow enregistré par une version antérieure à 2.19.0. | | `workflow_code_failure_requires_corrected_definition` | Le code du workflow a levé une exception et la définition n’a pas changé, donc le même code la lèverait à nouveau. | -| `unsupported_history` | L’historique avant l’échec contient une étape que le redrive ne peut pas réutiliser, comme un workflow enfant ou un minuteur annulé. | +| `unsupported_history` | L’historique avant l’échec contient une étape que le redrive ne peut pas réutiliser, comme un minuteur annulé. Avant Workflow 2.26, tout workflow enfant. | +| `unsupported_open_child` | Un appel de workflow enfant avant l’échec ne s’est jamais fermé. Workflow 2.26 et versions ultérieures. | +| `unsupported_child_outcome` | Un workflow enfant avant l’échec a échoué, a été annulé ou a été arrêté de force. Workflow 2.26 et versions ultérieures. | +| `unsupported_child_workflow` | Un appel de workflow enfant se trouve dans un groupe parallèle ou une portée d’annulation, a fait l’objet d’une nouvelle tentative ou d’un continue-as-new, ou ses événements ne désignent pas un seul appel enfant. Workflow 2.26 et versions ultérieures. | +| `external_child_result_not_supported` | Le résultat d’un workflow enfant terminé se trouve dans le stockage externe des payloads. Workflow 2.26 et versions ultérieures. | +| `unavailable_child_result` | Le résultat d’un workflow enfant terminé ne peut pas être décodé. Workflow 2.26 et versions ultérieures. | | `unsupported_local_activity` | L’historique contient une activité locale. | | `unsupported_timer` | L’historique contient un délai de condition ou de signal, un minuteur de nettoyage d’annulation, ou un minuteur dans une portée d’annulation ou un groupe parallèle. | | `incomplete_timer_step` | Il manque à une étape de minuteur son événement de planification ou de déclenchement. | @@ -228,7 +235,7 @@ Un refus indique la première règle non respectée : | `definition_incompatible_with_prefix` | Le code corrigé ne peut pas rejouer les étapes terminées. `definition_mismatch` indique la première étape qui diffère. | | `definition_check_over_budget` | L’historique terminé dépasse le budget d’historique autorisé par la vérification de relecture. | | `definition_change_requires_replay_check` | Un worker de service a démarré l’exécution, donc le redrive ne peut pas vérifier une définition modifiée. | -| `service_redrive_history_not_qualified` | Un worker de service a démarré l’exécution, et les étapes avant l’échec comprennent un upsert de mémo, un upsert d’attribut de recherche, une attente de signal ou un update appliqué. Le redrive refuse ces étapes pour les exécutions de service jusqu’à pouvoir vérifier, pour chaque runtime de SDK, qu’il sait les rejouer. | +| `service_redrive_history_not_qualified` | Un worker de service a démarré l’exécution, et les étapes avant l’échec comprennent un upsert de mémo, un upsert d’attribut de recherche, une attente de signal, un update appliqué ou un appel de workflow enfant terminé. Le redrive refuse ces étapes pour les exécutions de service jusqu’à pouvoir vérifier, pour chaque runtime de SDK, qu’il sait les rejouer. | | `request_id_already_used` | Le `request_id` a déjà servi pour un autre redrive de l’instance. | | `already_redriven` | Signalé par le détail d’exécution et `describe()` pour une exécution qui a déjà fait l’objet d’un redrive. Une demande de redrive pour cette exécution renvoie le successeur existant. | | `invalid_request_id` | Le `request_id` dépasse 191 caractères. | @@ -250,6 +257,8 @@ Dans Workflow 2.20.0 et versions ultérieures, le détail d’exécution et `des ### Versions antérieures et Server natif {#redrive-earlier-releases} +Les versions de Workflow antérieures à 2.26.0 refusent tout workflow enfant dans l’historique avec `unsupported_history`. Elles ignorent `reused_recorded_at` sur les événements de workflow enfant, si bien qu’un successeur 2.26.0 qui a réutilisé un appel enfant peut y être rejoué avec un temps de workflow différent, et des échéances différentes, après l’appel. Elles refusent aussi de le relancer à nouveau par redrive. Dès qu’un tel successeur existe, gardez les workers en 2.26.0 ou ultérieur, ou vérifiez qu’aucun historique de ce type ne peut être rejoué, avant de revenir à une version antérieure. + Workflow 2.20.0 ne refuse rien de ce que 2.20.1 accepte. Dans 2.20.0, `outbox()->sendReference()` dans le code de workflow réutilisé envoie de nouveau, et un `inbox()->receive()` rejoué peut renvoyer d’autres messages ou aucun, ou consommer un message plus récent ([workflow#1010](https://github.com/durable-workflow/workflow/issues/1010)). Workflow 2.19.0 refuse un update appliqué (`unsupported_history`). Il refuse aussi le redrive d’un successeur qui a réutilisé un update (`unsupported_history`) ou une attente de signal (`mismatched_signal_receipt`). Le détail d’exécution et `describe()` affichent les liens de redrive comme repli de diagnostic. diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/features/child-workflows.md b/i18n/fr/docusaurus-plugin-content-docs/current/features/child-workflows.md index e9dafa391bc..9106a5ccfac 100644 --- a/i18n/fr/docusaurus-plugin-content-docs/current/features/child-workflows.md +++ b/i18n/fr/docusaurus-plugin-content-docs/current/features/child-workflows.md @@ -200,7 +200,7 @@ $results = all([ - À toute clôture du parent, le moteur recherche les liens enfants ouverts avec une politique autre qu’abandon et envoie à chacun la commande adaptée : demande coopérative, annulation ou arrêt forcé. - Si l’enfant est déjà clôturé lors de l’application, aucune action n’est exécutée et la commande est ignorée silencieusement. - L’application est faite au mieux : le rejet d’une commande enfant (par exemple déjà terminal) n’affecte pas la clôture du parent. Un succès enregistre `ParentClosePolicyApplied` sur le parent. Un échec enregistre `ParentClosePolicyFailed` pour distinguer les applications réussies des échecs silencieux. -- La continuation dans une nouvelle exécution ne déclenche **pas** cette politique, car l’instance reste active. +- La continuation dans une nouvelle exécution ne déclenche **pas** cette politique, car l’instance reste active. Depuis Workflow 2.26, c’est la dernière exécution de la chaîne qui l’applique. Voir [Continuation et enfants ouverts](#continue-as-new-and-open-children). ### Matrice des résultats du parent {#parent-disposition-matrix} @@ -213,9 +213,21 @@ La politique s’applique à chaque résultat terminal du parent et reste inacti | Expiré | Oui | Après l’enregistrement de `WorkflowTimedOut` pour les expirations d’exécution individuelle ou globale. | | Annulé | Oui | Après la clôture du parent par la commande acceptée `CancelRequested`. | | Arrêté de force | Oui | Après la clôture du parent par la commande acceptée `TerminateRequested`. | -| Continuation | Non | L’instance reste active dans la nouvelle exécution. Les liens enfants existants sont redirigés vers celle-ci avec leur politique initiale. | +| Continuation | Non | L’instance reste active dans la nouvelle exécution. Depuis Workflow 2.26, l’exécution suivante prend en charge la supervision des enfants ouverts, et la dernière exécution de la chaîne applique leur politique. | | Réinitialisation | Non applicable actuellement | Le runtime v2 n’expose ni commande autonome de réinitialisation ni résultat terminal correspondant. Toute future réinitialisation ou réparation clôturant ou remplaçant un parent devra définir le transfert de propriété des enfants. Si l’ancienne exécution devient terminale, elle doit appliquer la politique avant de cesser de posséder ses enfants ouverts. | +### Continuation et enfants ouverts {#continue-as-new-and-open-children} + +Dans Workflow 2.26 et les versions ultérieures, un parent qui continue dans une nouvelle exécution alors que des enfants qu’il a démarrés sont encore ouverts les transmet à l’exécution suivante, dans la même transaction. Les exécutions embarquées et en mode service se comportent de la même façon : + +- Chaque enfant ouvert reçoit une ligne dans la table `workflow_child_supervisions`, créée par la migration 2.26. Un enfant déjà clôturé n’est pas transmis. +- Le lien enfant, l’appel enfant, la séquence, les échéances et la politique de clôture du parent restent tels que l’exécution de départ les a enregistrés. Quand l’exécution suivante continue à son tour dans une nouvelle exécution, elle transmet de nouveau les enfants. +- Quand la dernière exécution de la chaîne se termine, échoue, expire, est annulée ou est arrêtée de force, elle applique la politique de chaque enfant et enregistre `ParentClosePolicyApplied` ou `ParentClosePolicyFailed` dans son propre historique. `abandon` reste `abandon`. L’exécution antérieure clôturée ne reçoit aucun nouvel historique. +- L’exécution suivante n’a aucun handle sur ces enfants, et leurs résultats ne lui sont pas remis. Passez tout ce dont l’exécution suivante a besoin dans les arguments de `continueAsNew()`. +- Un enfant transmis qui échoue fait l’objet d’une nouvelle tentative selon la politique de nouvelles tentatives enregistrée par l’exécution de départ, avec la même identité d’appel enfant et le même compteur de tentatives, tant qu’une exécution de la chaîne le supervise encore. Le `WorkflowStarted` de l’exécution de nouvelle tentative désigne l’exécution de départ comme parent, et la dernière exécution de la chaîne applique la politique de clôture du parent à l’exécution de nouvelle tentative. L’échec est définitif une fois les tentatives épuisées, si l’échec n’est pas réessayable ou si la chaîne est clôturée. + +Avant 2.26, ces enfants continuaient à s’exécuter après la clôture de la chaîne et leur politique n’était jamais appliquée, et un enfant qui échouait après la continuation de son parent dans une nouvelle exécution ne faisait pas l’objet d’une nouvelle tentative. Voir les [notes de version 2.26.0](https://github.com/durable-workflow/workflow/releases/tag/2.26.0). + ### Quand utiliser chaque politique {#when-to-use-each-policy} **Abandonner** (par défaut) convient aux enfants représentant un travail indépendant devant aboutir quel que soit le sort du parent, par exemple un workflow de notification ou une tâche de nettoyage à terminer. diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/features/continue-as-new.md b/i18n/fr/docusaurus-plugin-content-docs/current/features/continue-as-new.md index 8f8e9a84cb1..b44789bf521 100644 --- a/i18n/fr/docusaurus-plugin-content-docs/current/features/continue-as-new.md +++ b/i18n/fr/docusaurus-plugin-content-docs/current/features/continue-as-new.md @@ -82,6 +82,10 @@ Les boucles longues peuvent réduire leur historique sans inventer un nouvel ide Le code du workflow peut consulter la longueur courante de l’historique et un indicateur de recommandation de continuation via un contexte explicite du runtime. Les boucles longues peuvent ainsi passer le relais volontairement avant d’atteindre des limites de budget d’historique. +Dans Workflow 2.26 et les versions ultérieures, utilisez `shouldContinueAsNewAtStep()` et `historyBudgetAtStep()`. Elles ne comptent que l’historique enregistré avant l’étape courante du workflow, si bien que la même ligne renvoie la même réponse à chaque relecture. Une boucle qui vérifie le budget à chaque itération continue dans une nouvelle exécution une seule fois, à la première itération qui dépasse le seuil. + +Les anciennes méthodes lisent tout l’historique courant. Dans une boucle, une itération antérieure peut voir un total ultérieur lors de la relecture et prendre une autre branche que la première fois. Elles sont inchangées, si bien que les exécutions qui ont déjà décidé avec elles continuent d’être rejouées. + ```php use function Workflow\V2\activity; use function Workflow\V2\continueAsNew; @@ -109,6 +113,8 @@ class PollingWorkflow extends Workflow | `$this->historyLength()` | `int` | Nombre d’événements d’historique de l’exécution courante | | `$this->historySize()` | `int` | Taille totale des événements d’historique en octets | | `$this->shouldContinueAsNew()` | `bool` | `true` lorsque l’exécution dépasse le budget configuré d’événements ou d’octets | +| `$this->historyBudgetAtStep()` | `array` | Le budget à l’étape courante : `history_event_count`, `history_size_bytes`, `history_fan_out`, `continue_as_new_recommended`, `pressure`, `pressure_dimensions` et `observation` (`step_prefix.v1`). Workflow 2.26 et versions ultérieures. | +| `$this->shouldContinueAsNewAtStep()` | `bool` | `continue_as_new_recommended` issu de `historyBudgetAtStep()`. Utilisez-la dans les boucles. Workflow 2.26 et versions ultérieures. | ### Configuration {#configuration} @@ -124,7 +130,7 @@ Les seuils de recommandation de continuation sont configurables : ], ``` -`shouldContinueAsNew()` renvoie `true` dès que l’un des seuils est dépassé. Les résumés suivent aussi `history_event_count`, `history_size_bytes` et `continue_as_new_recommended` pour que Waterline signale les exécutions longues dans les vues du parc. +`shouldContinueAsNew()` et `shouldContinueAsNewAtStep()` renvoient `true` dès que l’un des seuils est dépassé. Les résumés suivent aussi `history_event_count`, `history_size_bytes` et `continue_as_new_recommended` pour que Waterline signale les exécutions longues dans les vues du parc. ## Transmission des métadonnées {#metadata-carry-forward} @@ -164,6 +170,8 @@ class PollingWorkflow extends Workflow } ``` +Un parent qui continue dans une nouvelle exécution alors que des workflows enfants qu’il a démarrés sont encore ouverts les transmet à l’exécution suivante. Voir [Continuation et enfants ouverts](./child-workflows.md#continue-as-new-and-open-children). + Pour les boucles longues d’entrées humaines ou d’assistant, préférez la façade native `$this->inbox()` / `$this->outbox()` des [Flux de messages](./message-streams.md). Les messages de flux en attente et la position du curseur passent à la nouvelle diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/features/search-attributes.md b/i18n/fr/docusaurus-plugin-content-docs/current/features/search-attributes.md index fea36aa3e05..7603835bbbf 100644 --- a/i18n/fr/docusaurus-plugin-content-docs/current/features/search-attributes.md +++ b/i18n/fr/docusaurus-plugin-content-docs/current/features/search-attributes.md @@ -105,7 +105,7 @@ Sur le Server, vous pouvez enregistrer un attribut de recherche avec un type via L'enregistrement ne contraint que les clés que vous enregistrez. À partir du Server natif 3.5.0, une clé non enregistrée reste acceptée et son type est déduit, comme dans un namespace sans attribut enregistré. Enregistrer un attribut ne casse pas les workflows en cours qui font un upsert d'autres clés. PHP Server 2.x et le Server natif antérieur à 3.5.0 refusent toute clé non enregistrée dès qu'un attribut est enregistré. Sur ces versions, enregistrez donc toutes les clés utilisées par vos workflows avant d'enregistrer la première. -Supprimer un enregistrement arrête la vérification de cette clé. Les valeurs stockées et les workflows en cours ne changent pas, et les upserts ultérieurs de la clé sont de nouveau déduits. +Supprimer un enregistrement arrête la vérification de cette clé. Les valeurs stockées et les workflows en cours ne changent pas, et les upserts ultérieurs de la clé sont de nouveau déduits. Sur le Server natif, une requête de liste qui filtre sur une clé non enregistrée, y compris une clé dont vous avez supprimé l'enregistrement, est refusée, car la clé n'est pas définie dans le namespace. Pour changer le type d'un attribut, enregistrez un nouveau nom d'attribut avec le nouveau type, modifiez vos workflows pour qu'ils l'écrivent, puis filtrez sur le nouveau nom une fois les exécutions existantes à jour. Supprimer puis réenregistrer le même nom avec un autre type laisse les valeurs antérieures dans l'ancien type. diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/polyglot/php.md b/i18n/fr/docusaurus-plugin-content-docs/current/polyglot/php.md index 42204e149f2..c9293cbdf28 100644 --- a/i18n/fr/docusaurus-plugin-content-docs/current/polyglot/php.md +++ b/i18n/fr/docusaurus-plugin-content-docs/current/polyglot/php.md @@ -308,7 +308,7 @@ Nouveautés de ces versions : - **Suffixes d'historique sticky (3.14).** Les workers annoncent `sticky_history_suffix`. Sur Server 3.5.0 ou ultérieur, un worker qui détient déjà l'historique d'une exécution ne reçoit que les événements postérieurs à la séquence mise en cache. Un suffixe qui ne prolonge pas exactement l'historique en cache est ignoré et l'historique complet est récupéré. Les Servers plus anciens continuent d'envoyer l'historique complet. - **Origine du schedule (3.13).** `WorkflowContext::scheduleOrigin()` renvoie l'identifiant du schedule, l'heure d'occurrence et le numéro de déclenchement qui ont démarré l'exécution, ou `null` pour un démarrage ordinaire. La valeur est identique au rejeu. Depuis Server 3.5.0, une exécution qui continue dans une nouvelle exécution conserve son origine de schedule. -- **Continuations d'activité (3.12).** Passez `enableActivityContinuation: true` au constructeur de `Worker` pour envoyer les commandes suivantes du workflow avec un résultat d'activité réussi quand le Server annonce `activity_workflow_continuation` (Server native 3.4.0 ou ultérieur). La valeur par défaut est `false`. Utilisez 3.12.1 ou ultérieur si vous l'activez, et videz ou désactivez ces workers avant de rétrograder le Server ou d'ajouter des nœuds Server plus anciens. +- **Continuations d'activité (3.12).** Passez `enableActivityContinuation: true` au constructeur de `Worker` pour envoyer les commandes suivantes du workflow avec un résultat d'activité réussi quand le Server annonce `activity_workflow_continuation` (Server native 3.4.0 ou ultérieur). La valeur par défaut est `false`. L'activer coûte actuellement du débit : dans notre benchmark sous charge, les workflows étaient 24 à 49 % plus lents avec l'option activée et utilisaient deux fois plus de transactions de base de données ([mesure](https://github.com/durable-workflow/server/issues/1078)). Utilisez 3.12.1 ou ultérieur si vous l'activez, et videz ou désactivez ces workers avant de rétrograder le Server ou d'ajouter des nœuds Server plus anciens. Voir le [journal des modifications 3.14.0](https://github.com/durable-workflow/sdk-php/blob/3.14.0/CHANGELOG.md) pour la liste complète. diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/testing.md b/i18n/fr/docusaurus-plugin-content-docs/current/testing.md index 3bcdfe75336..a2d7fa15e77 100644 --- a/i18n/fr/docusaurus-plugin-content-docs/current/testing.md +++ b/i18n/fr/docusaurus-plugin-content-docs/current/testing.md @@ -383,7 +383,9 @@ d'historique. Vous pouvez donc vérifier aussi les lignes `WorkflowCommand` et Les champs `HistoryBudget` (`history_event_count`, `history_size_bytes`, `continue_as_new_recommended`) sont exposés dans la projection de résumé et via `RunDetailView`. Dans votre code, la classe de base `Workflow` les expose par -`$this->historyLength()`, `$this->historySize()` et `$this->shouldContinueAsNew()` : +`$this->historyLength()`, `$this->historySize()` et `$this->shouldContinueAsNew()`. Dans une boucle, +utilisez `$this->shouldContinueAsNewAtStep()` (Workflow 2.26 et versions ultérieures), +qui donne la même réponse à chaque relecture : ```php use Workflow\V2\Workflow; @@ -395,7 +397,7 @@ final class LongRunningWorkflow extends Workflow while (true) { // ... process work ... - if ($this->shouldContinueAsNew()) { + if ($this->shouldContinueAsNewAtStep()) { Workflow::continueAsNew($this->carryForwardState()); } } diff --git a/i18n/fr/source-hashes.json b/i18n/fr/source-hashes.json index aaa9e3d33f5..29802b30c7c 100644 --- a/i18n/fr/source-hashes.json +++ b/i18n/fr/source-hashes.json @@ -4,7 +4,7 @@ "ai-agent-workflow-engine.md": "28016466b179adbabdff6467ce351100c9bee48529a8bec9df7ec22c8d786d4d", "ai-assisted-development.md": "b246bb60585fb7a69bc534978f470f3f16e899e1f8f203ba0847d2d11b8a1ec3", "capabilities.md": "d9a2bbc0d04adf8cb3f4c7f42d779a43aafab60791210305e7e476c0499528fc", - "compatibility.md": "567310faf420fbd5229c5eef69721e8b7d09f033333cbaec21b72acaf81b6690", + "compatibility.md": "ad5c8519be03ae1e7b6e5e03b05a886862fd67c603b241ecb5baf2be5cd59610", "configuration/customization-matrix.md": "3d115863eaee7852b541bcd01615f424cc19c5847c7cd7d75e5ae63bc3f5cc78", "configuration/database-connection.md": "cc83ae77133236309506fa44d39bfd0c939c32a6154c0bd6099bc64c83bdaec9", "configuration/ensuring-same-server.md": "6c665f37cc198c7b1a775a60a94aab5ff4e55383385e76f1834c7840559b512a", @@ -24,18 +24,18 @@ "defining-workflows/activities.md": "05b46f73477a0bbd5f21d17ac37def8a8eac53f1e629155805c98cc46e75b418", "defining-workflows/passing-data.md": "c5d36126b0b15f1780119f6418e8bbe5a63e03353be5a0bb69385206ef0ad635", "defining-workflows/starting-workflows.md": "722b80454b577b0715ff50db70c7cda2cd02c34c505dd1219a83307852d325a4", - "defining-workflows/workflow-api.md": "a6150e75302323b49f350159ce3568a51a19701bb81829915615f754592ee79c", + "defining-workflows/workflow-api.md": "3c13894c1fdbe77bb1379c62bbdb0ef213c81f1cba5b477d45402dcc7fe87237", "defining-workflows/workflow-id.md": "ca3b43253a748b27dca1af9f82fcf8c4c133e14f13e1b82eaa1ca2ed0996d4bf", "defining-workflows/workflow-status.md": "8e8cb27ff44c890d489d89bf166375acfdfaecabd990a2235e106fab1592d529", "defining-workflows/workflows.md": "f467bc73de32aa5d722c61ce085065460382ae7dd44cea4625847d9fcdc4c97c", "deployment.md": "6aa439b1ebfdc2affccaf6fe6fff7519776a4ffcad8d3cb5956b665e7c97257f", - "failures-and-recovery.md": "598b538e2bcb6a40a4f2d4c0c462705bab30ef96767144f6590c2cc93b68a98a", + "failures-and-recovery.md": "4209521a8783939d458658a7afea64124c34571080c97feb2868a273db88db3e", "features/activity-execution-model.md": "e8c37520ae46a7efb30438f4fc06bf893c1df430cb1f92c48963697adaf09082", "features/cancel-and-terminate.md": "cedd1e6c51dfa551e00edc1d39739ff1f67d558d2a0be92143f478cb6111536b", - "features/child-workflows.md": "57016591fb8816aed7b077e204f1c80f9c6a8dff7501bc00a141c41a4607306b", + "features/child-workflows.md": "278b634b8b48b94203309cdba27d6116897a2919cab19628add8cd85dadb08d3", "features/concurrency.md": "a7a3eb2274f7b14faf722494569b7663c07ab48afdf2e9225e58914b84cacbb4", "features/condition-waits.md": "451261eda990c9591a0db69839d872184b5c64da6b537a582133095b8d4b599e", - "features/continue-as-new.md": "50c79f317155e052a3f2f37d198a71bdfc496a454905293f40cf09d73138f25b", + "features/continue-as-new.md": "a5309192c685abeb5295071d423824ae2287e68d247a6661f18d3ab21f9bdc9c", "features/events.md": "c466df05908748489226a3d1410c9203cf6f2986a4bb7539db1c5f82715abc7b", "features/external-payload-storage.md": "acc312fa2f50a43c96e1d235439124d28a7048f0bf3abac34319467fcbf7e898", "features/heartbeats.md": "4fce9636d68c89f29f259d52e463cd67eccf0bc55ad4d53338ed03329892b365", @@ -45,7 +45,7 @@ "features/queries.md": "c66dd9542a062edd8158a46cebc9f1bf926aaf3599dca4a3122bd9860df6e2a2", "features/sagas.md": "046ba5661ccb5ac71a236356d243b021d9830123e3798afce491118434e83820", "features/schedules.md": "40d30b2767e7ed043e2b0c7180915c256accea3e7a3401c38d1bf75bfe1c2213", - "features/search-attributes.md": "567d89858cd82e86672b210154001a272b17a5f87e13dbfa7de1b8e093d615b8", + "features/search-attributes.md": "bb66d83f64e0098354d86ac237e6867b9819098044101ba9a60a6a00a3961dd1", "features/service-operations.md": "912131c0a8ef393040a933fb4a66e68abcb9d475a3ebd47c85287d4032f45a0e", "features/side-effects.md": "abdccab8d6fc1a12b3eff8a4ccc58730ac36f523559b4ad89c5c2a8d201a3b86", "features/signal+timer.md": "a05fc480544fa71f6c9b215ad3417f71b8475dd81f9de8ee18d7a3b69ac33a23", @@ -80,7 +80,7 @@ "polyglot/invocable-carrier.md": "d32d8b5c7c33204b342f977e0af734166d91e96073db1a49ccb4d414a6d67380", "polyglot/invocable-php-handler.md": "3b678eb1d69fe32dfcfdc05d36b33e49e01b79d7216bd784f6a61a6f1c3c3a13", "polyglot/namespace-auth-workers.md": "2b4078ceb74b849f12cb1975b410ff8e7266cd4345f6cf1d4dd906db12460ffb", - "polyglot/php.md": "04f7eeebf842bbcd2f278f96ee21fbbf4f97d424a27e717d65e1c73273bce095", + "polyglot/php.md": "309e83622754b9d9abc65807280f2dab175a009054a001456ef1316776f11101", "polyglot/polling-patterns.md": "30875099a23731c6c471b481a771378acc6ff57eed2fda4405a509057534c989", "polyglot/portable-worker-affinity.md": "40973c6a31a76845b4f95e9a505e68ad76abd5174bbdccf37993cdebc8904959", "polyglot/prerelease-history-migration.md": "a57f05f492228a8a67791f9152648a1e5f80856325b78777cf63b6ef49b7413c", @@ -105,6 +105,6 @@ "sdk-neutrality.md": "7b0714c123ade4904591870fc20e9a797da1e5485b2a6c87ca3eaa00c5de6ed6", "sponsors.md": "e85e14375743ca8fa50e3a48f894b160e28272573aa88480064f74010ebee98a", "support.md": "706807b3902599dda6080f632ec1f893017ea18bbe9585f533dcdbd6d85f4621", - "testing.md": "250bc7dfd46f99eaeb392b329947813b064bda72026645198e3aefc80043a813", + "testing.md": "176abf226936c7711c2df523fb8a94e92fcf62e6f804d99f2e32b9135f626547", "waterline-operator-api.md": "2aca03b2c14100060b40be0bb033a82525ba924908834e9060ec746ead26f36d" } diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/compatibility.md b/i18n/ja/docusaurus-plugin-content-docs/current/compatibility.md index 890ace43481..de5e8265344 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/compatibility.md +++ b/i18n/ja/docusaurus-plugin-content-docs/current/compatibility.md @@ -66,12 +66,12 @@ PHP と Laravel の要件を比較する前にパッケージのリリースを | パッケージ系列 | PHP | Laravel | | --- | --- | --- | -| 現在の組み込み Workflow 2.24 | 8.x 系の PHP 8.2 以降。Laravel 13 は PHP 8.3 以降 | `^12.69.0` または `^13.30.0` | +| 現在の組み込み Workflow 2.26 | 8.x 系の PHP 8.2 以降。Laravel 13 は PHP 8.3 以降 | `^12.69.0` または `^13.30.0` | | 組み込み Workflow 2.20.5 | PHP `^8.1`。Laravel 自身の最低要件も適用 | `^10.50.4`、`^11.56.1`、`^12.69.0` または `^13.30.0` | | 公開済み PHP SDK 3.14 | 基本 SDK は PHP `^8.1`。Laravel ブリッジは PHP `^8.2` が必要で、Laravel 13 は PHP 8.3 以降 | `^12.69.0` または `^13.30.0` | | PHP SDK 3.9.5 | 基本 SDK は PHP `^8.1`。Laravel ブリッジはフレームワークの最低要件にも従う | `^10.50.4`、`^11.56.1`、`^12.69.0` または `^13.30.0` | -[公開済み組み込みアップグレード契約](https://github.com/durable-workflow/workflow/blob/2.24.0/resources/laravel-embedded-upgrade-contract.json) +[公開済み組み込みアップグレード契約](https://github.com/durable-workflow/workflow/blob/2.26.0/resources/laravel-embedded-upgrade-contract.json) と各リリースの `composer.json` がパッケージの根拠です。現在の組み込みリリースは Laravel 12/PHP 8.2~8.4 と Laravel 13/PHP 8.3~8.4 で検証されています。 PHP 8.1 と Laravel 10/11 のサポートは終了しました。 @@ -110,6 +110,16 @@ Workflow 2.23 と 2.24 は 2.21 のサポート下限と組み込みワーカー [2.23.0](https://github.com/durable-workflow/workflow/releases/tag/2.23.0), [2.23.1](https://github.com/durable-workflow/workflow/releases/tag/2.23.1), [2.23.2](https://github.com/durable-workflow/workflow/releases/tag/2.23.2)、[2.24.0](https://github.com/durable-workflow/workflow/releases/tag/2.24.0) のリリースノートを参照してください。 +Workflow 2.25 と 2.26 は 2.21 のサポート下限と組み込みワーカープロトコル `1.22` を維持します。2.25 はデータベースマイグレーションを追加しません。2.26 は 1 つ追加するため、アップグレード時に `php artisan migrate` を実行してください。このマイグレーションは `workflow_child_supervisions` テーブルを作成します。アップグレード前に確認すべき変更: + +- 2.26 以降、自身が起動した子がまだ開いている間に continue-as-new した親は、それらの子を継続先の実行に引き渡します。チェーンの最後の実行がそれらの親終了時ポリシーを適用し、失敗した子は記録済みのリトライポリシーに従って引き続きリトライされます。[Continue-as-new と開いている子](./features/child-workflows.md#continue-as-new-and-open-children)を参照してください。 +- 2.26 以降、既存の行を埋める以前のリリースのマイグレーション(`2026_07_13`、`2026_09_24`、`2026_09_29`、`2026_10_11`)は、バックフィルの間ずっとテーブルをロックすることはなくなりました。まず列を追加し、行を小さなバッチで埋めてから、書き込みをブロックせずにインデックスを作成します。いずれかが中断された場合は、`php artisan migrate` を再実行してください。これらをすでに実行済みのインストールには影響しません。 +- 2.26 以降、redrive は失敗前に完了した子ワークフローを再利用します。2.26 より前のリリースは、そのような後継実行を再利用された子の後で異なるワークフロー時刻でリプレイするため、そうした後継実行が存在する場合はワーカーを 2.26 以降に保ってください。[失敗した実行を redrive する](./failures-and-recovery.md#redrive)を参照してください。 +- 2.26 以降、`historyBudgetAtStep()` と `shouldContinueAsNewAtStep()` はどのリプレイでも同じように履歴の使用量上限を読み取ります。ループではこれらを使ってください。[履歴の使用量上限](./features/continue-as-new.md#history-budget)を参照してください。 +- 2.25 以降、固定のメモまたは検索属性の上限を超えると、`InvalidArgumentException` ではなく `StructuralLimitExceededException` が発生し、`memo_size_bytes` の既定値は 65,536 です。[構造上の制限](./constraints/structural-limits.md)を参照してください。 + +[2.25.0](https://github.com/durable-workflow/workflow/releases/tag/2.25.0)、[2.26.0](https://github.com/durable-workflow/workflow/releases/tag/2.26.0) のリリースノートを参照してください。 + ## 安定性レベル {#stability-levels} Durable Workflow の各公開インターフェースは、次の安定性レベルを厳密に一つ持ちます。分類は明示的です。未分類のインターフェースは公開ではありません。 diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/defining-workflows/workflow-api.md b/i18n/ja/docusaurus-plugin-content-docs/current/defining-workflows/workflow-api.md index b6c9d5ec843..b00840c94b4 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/defining-workflows/workflow-api.md +++ b/i18n/ja/docusaurus-plugin-content-docs/current/defining-workflows/workflow-api.md @@ -46,6 +46,8 @@ abstract class Workflow public function historyLength(): int; public function historySize(): int; public function shouldContinueAsNew(): bool; + public function historyBudgetAtStep(): array; + public function shouldContinueAsNewAtStep(): bool; } ``` @@ -58,6 +60,8 @@ abstract class Workflow | `historyLength()` | 履歴の規模を件数で判断する指標が必要な場合。 | 現在の履歴イベント件数。 | | `historySize()` | 履歴の規模をバイト数で判断する指標が必要な場合。 | 保存済み履歴のおおよそのバイト数。 | | `shouldContinueAsNew()` | 履歴コストが増える前に実行を切り替える場合。 | 設定した履歴の目安が切り替えを推奨すると `true`。 | +| `historyBudgetAtStep()` | ループなどで、1 つの実行の中で使用量上限を複数回読み取る場合(Workflow 2.26 以降)。 | 現在のステップ時点の使用量カウンター。どのリプレイでも同じ値。 | +| `shouldContinueAsNewAtStep()` | ループで実行を切り替えるかどうかを判断する場合(Workflow 2.26 以降)。 | 現在のステップより前の履歴が設定した上限を超えると `true`。 | ## 永続コマンド {#durable-commands} diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/failures-and-recovery.md b/i18n/ja/docusaurus-plugin-content-docs/current/failures-and-recovery.md index 2e1dd282e8e..e50edcddf28 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/failures-and-recovery.md +++ b/i18n/ja/docusaurus-plugin-content-docs/current/failures-and-recovery.md @@ -114,6 +114,7 @@ redrive は、失敗した実行を同じワークフローインスタンスの - 失敗したステップより前にワークフローコードが upsert したメモや検索属性は、ステップ順に再利用され、後継実行は同じ値を保持します。 - シグナルを受信して適用したシグナル待機(`await('name')`)は、そのシグナルの値とともに再利用されます。シグナルが再び配信されることはありません。 - 失敗したステップより前に受け付けられ、適用され、完了した更新は、同じ位置に改めて記録されます。リプレイは記録された引数で更新ハンドラーを実行するので、ワークフローの状態は一致します。更新が再び配信されることはありません。拒否された更新と、実行前に失敗で閉じられた更新は除外されます。 +- Workflow 2.26 以降では、失敗したステップより前に完了した子ワークフロー呼び出しは、記録済みの結果を返します。子が再び開始されることはありません。後継実行はその呼び出しの `ChildWorkflowScheduled`、`ChildRunStarted`、`ChildRunCompleted` イベントを記録し、元の子インスタンス、子の実行、リンク ID、呼び出し ID を保持しますが、後継実行自身の子リンクは持ちません。 - 再利用されるワークフローコード内の `outbox()->sendReference()` と `inbox()->receive()` は、失敗した実行が送信または消費したメッセージを返します。再び送信や消費をすることはありません。元の呼び出しで何も見つからなかった receive は、リプレイ時にストリームを読み直します。 - Workflow 2.20.2 以降では、失敗した実行でまだ保留中の受信ストリームメッセージは後継実行に移ります。Workflow 2.20.1 以前はそれらを失敗した実行に残していたため、後継実行はそれらを受信しませんでした([workflow#1013](https://github.com/durable-workflow/workflow/issues/1013))。 - アクティビティ失敗で実行が終了した場合、失敗したアクティビティ呼び出しは、ワークフローコードの再試行ポリシーを使って新しいアクティビティ実行としてスケジュールされます。試行回数は最初からやり直しです。 @@ -123,7 +124,7 @@ redrive は、失敗した実行を同じワークフローインスタンスの - 後継実行は、失敗した実行のワークフロー全体の実行期限を引き継ぎます。実行ごとのタイムアウトは redrive の時点から改めて始まります。 - 再利用された各ステップには、`reused_from_run_id` と `reused_recorded_at` が付きます。 再利用された更新イベントやシグナルイベントでは、この 2 つは必ず対になります。 - ステップを再利用した後継実行は、さらに redrive できます。再利用されたシグナルや更新のペイロードは、最初に記録した実行を `workflow_run_id` に保持し、`reused_from_run_id` は redrive 元の実行を指し、再利用された各ステップは最初に実行された時刻を保持します。そのため、redrive の連鎖でも各ステップは一度だけ再利用されます。 -- 組み込みモードでは、後継実行の `Workflow::now()` は失敗した実行の開始時刻から始まります。リプレイは `reused_recorded_at` を使うので、再利用されたステップの後の `Workflow::now()` は失敗した実行での時刻と一致します。2 回目の redrive で再利用されたステップは、最初に実行された時刻を保持します。 +- 組み込みモードでは、後継実行の `Workflow::now()` は失敗した実行の開始時刻から始まります。リプレイは `reused_recorded_at` を使うので、再利用されたステップの後の `Workflow::now()` は失敗した実行での時刻と一致します。再利用された子ワークフロー呼び出しの後では、それは子が最初に終了した時刻です。2 回目の redrive で再利用されたステップは、最初に実行された時刻を保持します。 ### redrive を要求する {#request-a-redrive} @@ -179,11 +180,12 @@ redrive は、次の条件がすべて満たされるときに失敗した実行 - その実行がインスタンスの現在の実行である。 - アクティビティ失敗がワークフローコードに届いて捕捉されなかったか、ワークフローコードが例外を投げたか、構造上の上限で停止したために、実行が失敗した。ワークフローのタイムアウトで失敗した実行は拒否されます。 -- 失敗したステップより前のステップがすべて、完了したアクティビティ、副作用、バージョンマーカー、発火済みの `timer()`、メモまたは検索属性の upsert、シグナルを受信して適用したシグナル待機、同じ引数で受け付けられ、適用され、完了した更新のいずれかである。拒否された更新と、実行前に失敗で閉じられた更新は許可され、除外されます。アクティビティ、副作用、シグナル、更新のペイロードはインラインで保存されている必要があります。外部ペイロードストレージに保存されたペイロードは拒否されます。 +- 失敗したステップより前のステップがすべて、完了したアクティビティ、副作用、バージョンマーカー、発火済みの `timer()`、メモまたは検索属性の upsert、シグナルを受信して適用したシグナル待機、同じ引数で受け付けられ、適用され、完了した更新、または Workflow 2.26 以降では完了した子ワークフロー呼び出しのいずれかである。拒否された更新と、実行前に失敗で閉じられた更新は許可され、除外されます。アクティビティ、副作用、シグナル、更新、子の結果のペイロードはインラインで保存されている必要があります。外部ペイロードストレージに保存されたペイロードは拒否されます。 - ワークフロー定義が、実行開始時に記録されたフィンガープリントと一致する。または、`allow_definition_change` を指定し、修正したコードが完了したステップをリプレイできる。同じ定義でのワークフローコードの失敗は拒否されます。 - 実行期限を過ぎていない。 -- 実行に親ワークフロー、子ワークフロー、ローカルアクティビティがなく、入力がインラインで保存されている。 -- サービスワーカーが実行を開始した場合、失敗より前のステップがアクティビティ、副作用、バージョンマーカー、発火済みタイマーだけである。メモと検索属性の upsert、シグナル待機、適用済みの更新は、サービスモードの実行では拒否されます。 +- 実行に親ワークフローとローカルアクティビティがなく、入力がインラインで保存されている。Workflow 2.26 より前は、子ワークフローもないことが必要です。それ自体が子である実行は、親がすでに子の結果を記録しているため、redrive されることはありません。 +- 失敗したステップより前の各子ワークフロー呼び出しが、並列グループやキャンセルスコープの外で、リトライや continue-as-new なしに単独で完了している。 +- サービスワーカーが実行を開始した場合、失敗より前のステップがアクティビティ、副作用、バージョンマーカー、発火済みタイマーだけである。メモと検索属性の upsert、シグナル待機、適用済みの更新、完了した子ワークフロー呼び出しは、サービスモードの実行では拒否されます。 拒否では、最初に満たされなかった規則が示されます。 @@ -193,7 +195,12 @@ redrive は、次の条件がすべて満たされるときに失敗した実行 | `source_run_not_current` | インスタンスにより新しい実行があります。 | | `unrecorded_failure_boundary` | 実行の失敗に記録されたステップがありません。2.19.0 より前のリリースが記録したワークフローコードの失敗などが該当します。 | | `workflow_code_failure_requires_corrected_definition` | ワークフローコードが例外を投げ、定義が変更されていないため、同じコードが再び例外を投げます。 | -| `unsupported_history` | 失敗前の履歴に、子ワークフローやキャンセルされたタイマーなど、redrive が再利用できないステップが含まれています。 | +| `unsupported_history` | 失敗前の履歴に、キャンセルされたタイマーなど、redrive が再利用できないステップが含まれています。Workflow 2.26 より前は、あらゆる子ワークフローが該当します。 | +| `unsupported_open_child` | 失敗前の子ワークフロー呼び出しが閉じていません。Workflow 2.26 以降。 | +| `unsupported_child_outcome` | 失敗前の子ワークフローが失敗した、キャンセルされた、または強制終了されました。Workflow 2.26 以降。 | +| `unsupported_child_workflow` | 子ワークフロー呼び出しが並列グループやキャンセルスコープ内にある、リトライされたか continue-as-new した、またはそのイベントが 1 つの子呼び出しを示していません。Workflow 2.26 以降。 | +| `external_child_result_not_supported` | 完了した子ワークフローの結果が外部ペイロードストレージにあります。Workflow 2.26 以降。 | +| `unavailable_child_result` | 完了した子ワークフローの結果をデコードできません。Workflow 2.26 以降。 | | `unsupported_local_activity` | 履歴にローカルアクティビティが含まれています。 | | `unsupported_timer` | 履歴に、条件やシグナルのタイムアウト、キャンセル後のクリーンアップ用タイマー、またはキャンセルスコープや並列グループ内のタイマーが含まれています。 | | `incomplete_timer_step` | タイマーのステップに、スケジュールのイベントと発火のイベントの両方がそろっていません。 | @@ -220,7 +227,7 @@ redrive は、次の条件がすべて満たされるときに失敗した実行 | `definition_incompatible_with_prefix` | 修正したコードが完了したステップをリプレイできません。`definition_mismatch` が最初に異なるステップを示します。 | | `definition_check_over_budget` | 完了した履歴が、リプレイ確認で許される履歴の予算を超えています。 | | `definition_change_requires_replay_check` | サービスワーカーが実行を開始したため、redrive は変更された定義を確認できません。 | -| `service_redrive_history_not_qualified` | サービスワーカーが実行を開始し、失敗より前のステップにメモの upsert、検索属性の upsert、シグナル待機、適用済みの更新のいずれかが含まれています。redrive は、SDK ランタイムごとにこれらのステップをリプレイできるかを確認できるようになるまで、サービスモードの実行でこれらのステップを拒否します。 | +| `service_redrive_history_not_qualified` | サービスワーカーが実行を開始し、失敗より前のステップにメモの upsert、検索属性の upsert、シグナル待機、適用済みの更新、完了した子ワークフロー呼び出しのいずれかが含まれています。redrive は、SDK ランタイムごとにこれらのステップをリプレイできるかを確認できるようになるまで、サービスモードの実行でこれらのステップを拒否します。 | | `request_id_already_used` | その `request_id` は、インスタンスの別の redrive ですでに使われています。 | | `already_redriven` | すでに redrive された実行について、実行詳細と `describe()` が報告します。その実行への redrive リクエストは、代わりに既存の後継実行を返します。 | | `invalid_request_id` | `request_id` が 191 文字を超えています。 | @@ -242,6 +249,8 @@ Workflow 2.20.0 以降では、実行詳細と `describe()` が redrive のリ ### 以前のリリースとネイティブ Server {#redrive-earlier-releases} +2.26.0 より前の Workflow リリースは、履歴内のあらゆる子ワークフローを `unsupported_history` で拒否します。これらのリリースは子ワークフローイベントの `reused_recorded_at` を無視するため、子呼び出しを再利用した 2.26.0 の後継実行は、そのリリースではその呼び出しの後で異なるワークフロー時刻、異なる期限でリプレイされることがあります。また、その後継実行の再度の redrive も拒否します。そのような後継実行が存在する場合は、ロールバックの前に、ワーカーを 2.26.0 以降に保つか、そのような履歴がリプレイされないことを確認してください。 + Workflow 2.20.0 は、2.20.1 が受け付けるものを何も拒否しません。2.20.0 では、再利用されるワークフローコード内の `outbox()->sendReference()` が再び送信し、リプレイされた `inbox()->receive()` は別のメッセージを返すか、何も返さないか、より新しいメッセージを消費することがあります([workflow#1010](https://github.com/durable-workflow/workflow/issues/1010))。 Workflow 2.19.0 は、適用済みの更新を拒否します(`unsupported_history`)。また、更新(`unsupported_history`)またはシグナル待機(`mismatched_signal_receipt`)を再利用した後継実行の redrive も拒否します。実行詳細と `describe()` は、redrive のリンクを診断用のフォールバックとして示します。 diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/features/child-workflows.md b/i18n/ja/docusaurus-plugin-content-docs/current/features/child-workflows.md index 802349ff99d..4f85f53b339 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/features/child-workflows.md +++ b/i18n/ja/docusaurus-plugin-content-docs/current/features/child-workflows.md @@ -200,7 +200,7 @@ $results = all([ - 親がどの理由で閉じても、abandon 以外の未完了リンクを調べ、対応する要求・cancel・terminate を送ります。 - 適用時に子が既に閉じていれば何もせず、コマンドは黙ってスキップします。 - 適用はベストエフォートです。子が終端などで拒否しても親の終了に影響しません。成功なら親に `ParentClosePolicyApplied`、失敗なら `ParentClosePolicyFailed` を記録し、区別できます。 -- continue-as-new はインスタンスが新実行でアクティブなためポリシーを**発動しません**。 +- continue-as-new はインスタンスが新実行でアクティブなためポリシーを**発動しません**。Workflow 2.26 以降は、代わりにチェーンの最後の実行が適用します。[Continue-as-new と開いている子](#continue-as-new-and-open-children)を参照してください。 ### 親の終了結果の一覧 {#parent-disposition-matrix} @@ -213,9 +213,21 @@ $results = all([ | タイムアウト | はい | 実行・全体タイムアウトの `WorkflowTimedOut` 後。 | | キャンセル | はい | 受理した `CancelRequested` が親を閉じた後。 | | 強制終了 | はい | 受理した `TerminateRequested` が親を閉じた後。 | -| continue-as-new | いいえ | 子リンクは元のポリシーを保ち新実行に付け替えます。 | +| continue-as-new | いいえ | インスタンスは新しい実行でアクティブなままです。Workflow 2.26 以降は、継続先の実行が開いている子の監督を引き継ぎ、チェーンの最後の実行がそれらのポリシーを適用します。 | | リセット | 現在は対象外 | v2 は独立した reset コマンドや終端結果を提供しません。将来、親を閉じたり置換したりする reset・repair は子の所有権移転を定義し、旧実行を終端にするなら所有を手放す前にポリシーを適用する必要があります。 | +### Continue-as-new と開いている子 {#continue-as-new-and-open-children} + +Workflow 2.26 以降、自身が起動した子がまだ開いている間に continue-as-new した親は、同じトランザクション内でそれらの子を継続先の実行に引き渡します。組み込み実行とサービスモードの実行は同じように動作します。 + +- 開いている各子は、2.26 のマイグレーションが作成する `workflow_child_supervisions` テーブルに行を持ちます。すでに閉じた子は引き渡されません。 +- 子リンク、子の呼び出し、シーケンス、期限、親終了時ポリシーは、開始した実行が記録したとおりに保たれます。継続先の実行がさらに continue-as-new すると、子を再び引き渡します。 +- チェーンの最後の実行が完了、失敗、タイムアウト、キャンセル、強制終了で閉じると、各子のポリシーを適用し、自身の履歴に `ParentClosePolicyApplied` または `ParentClosePolicyFailed` を記録します。`abandon` は `abandon` のままです。閉じた以前の実行には新しい履歴は追加されません。 +- 継続先の実行はこれらの子のハンドルを持たず、子の結果も継続先の実行には届きません。次の実行に必要なものは `continueAsNew()` の引数で渡してください。 +- 引き渡された子が失敗した場合、チェーンのいずれかの実行がまだ監督している間は、開始した実行が記録したリトライポリシーに従い、同じ子の呼び出し識別子と試行回数でリトライされます。リトライ実行の `WorkflowStarted` は開始した実行を親として示し、チェーンの最後の実行がリトライ実行に親終了時ポリシーを適用します。試行回数を使い切った場合、失敗がリトライ不可の場合、またはチェーンが閉じた場合、失敗は確定します。 + +2.26 より前は、これらの子はチェーンが閉じた後も実行を続け、ポリシーは適用されませんでした。また、親が continue-as-new した後に失敗した子はリトライされませんでした。[2.26.0 のリリースノート](https://github.com/durable-workflow/workflow/releases/tag/2.26.0)を参照してください。 + ### 各ポリシーの用途 {#when-to-use-each-policy} **Abandon**(既定)は、通知や必須のクリーンアップなど、親の結果にかかわらず完了すべき独立処理に使います。 diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/features/continue-as-new.md b/i18n/ja/docusaurus-plugin-content-docs/current/features/continue-as-new.md index 047ea1cfc71..08548f05db4 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/features/continue-as-new.md +++ b/i18n/ja/docusaurus-plugin-content-docs/current/features/continue-as-new.md @@ -70,6 +70,10 @@ Core 2.7.0 と互換 Server は、実行のコマンド契約にハンドラー ワークフローコードは明示的なランタイムコンテキストから現在の履歴長と継続推奨フラグを参照できます。長期ループが履歴の使用量上限に達する前に、計画的に引き継げます。 +Workflow 2.26 以降では、`shouldContinueAsNewAtStep()` と `historyBudgetAtStep()` を使ってください。これらは現在のワークフローステップより前に記録された履歴だけを数えるため、同じ行はどのリプレイでも同じ結果を返します。反復ごとに使用量上限を確認するループは、しきい値を超えた最初の反復で 1 回だけ continue-as-new します。 + +従来のメソッドは現在の履歴全体を読み取ります。ループ内では、前の反復がリプレイ時にそれより後の合計値を見て、最初とは異なる分岐を取ることがあります。従来のメソッドは変更されていないため、すでにそれらで判断した実行は引き続きリプレイされます。 + ```php use function Workflow\V2\activity; use function Workflow\V2\continueAsNew; @@ -97,6 +101,8 @@ class PollingWorkflow extends Workflow | `$this->historyLength()` | `int` | 現在の実行の履歴イベント数 | | `$this->historySize()` | `int` | 履歴イベントの総バイト数 | | `$this->shouldContinueAsNew()` | `bool` | 設定した件数またはバイト数の上限を超えると `true` | +| `$this->historyBudgetAtStep()` | `array` | 現在のステップ時点の使用量: `history_event_count`、`history_size_bytes`、`history_fan_out`、`continue_as_new_recommended`、`pressure`、`pressure_dimensions`、`observation`(`step_prefix.v1`)。Workflow 2.26 以降。 | +| `$this->shouldContinueAsNewAtStep()` | `bool` | `historyBudgetAtStep()` の `continue_as_new_recommended`。ループではこれを使います。Workflow 2.26 以降。 | ### 設定 {#configuration} @@ -112,7 +118,7 @@ class PollingWorkflow extends Workflow ], ``` -いずれかのしきい値を超えると `shouldContinueAsNew()` は `true` です。実行サマリーも `history_event_count`、`history_size_bytes`、`continue_as_new_recommended` を追跡し、Waterline が一覧で長期実行を示せます。 +いずれかのしきい値を超えると `shouldContinueAsNew()` と `shouldContinueAsNewAtStep()` は `true` を返します。実行サマリーも `history_event_count`、`history_size_bytes`、`continue_as_new_recommended` を追跡し、Waterline が一覧で長期実行を示せます。 ## メタデータの引き継ぎ {#metadata-carry-forward} @@ -152,4 +158,6 @@ class PollingWorkflow extends Workflow } ``` +自身が起動した子ワークフローがまだ開いている間に continue-as-new した親は、それらの子を継続先の実行に引き渡します。[Continue-as-new と開いている子](./child-workflows.md#continue-as-new-and-open-children)を参照してください。 + 人の入力やアシスタントの長期ループには、正式な `$this->inbox()` / `$this->outbox()` の[メッセージストリーム](./message-streams.md)ファサードを優先します。保留中のストリームメッセージとカーソル位置は新しい実行に移り、消費済みメッセージは証拠として元の実行の履歴に残ります。Workflow 2.20.1 以前は、保留中のストリームメッセージを終了した実行に残していました([workflow#1018](https://github.com/durable-workflow/workflow/issues/1018)、2.20.2 で修正)。[メッセージストリーム](./message-streams.md#continue-as-new)を参照してください。 diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/features/search-attributes.md b/i18n/ja/docusaurus-plugin-content-docs/current/features/search-attributes.md index 9ed17c3fdc3..d607c9bcbb8 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/features/search-attributes.md +++ b/i18n/ja/docusaurus-plugin-content-docs/current/features/search-attributes.md @@ -105,7 +105,7 @@ Server では、`POST /api/search-attributes` で型を指定して検索属性 登録が制約するのは、登録したキーだけです。ネイティブ Server 3.5.0 以降では、登録されていないキーも引き続き受け付けられ、登録済み属性のない namespace と同じように型が推論されます。1 つの属性を登録しても、別のキーを upsert する実行中のワークフローは壊れません。PHP Server 2.x と 3.5.0 より前のネイティブ Server は、いずれかの属性が登録されると未登録のキーをすべて拒否します。そのため、これらでは最初の属性を登録する前に、ワークフローが使うすべてのキーを登録してください。 -登録を削除すると、そのキーの検証は行われなくなります。保存済みの値と実行中のワークフローは変わらず、以降のそのキーの upsert は再び型が推論されます。 +登録を削除すると、そのキーの検証は行われなくなります。保存済みの値と実行中のワークフローは変わらず、以降のそのキーの upsert は再び型が推論されます。ネイティブ Server では、登録されていないキー(登録を削除したキーを含む)でフィルターするリストクエリは、そのキーが namespace で定義されていないため拒否されます。 属性の型を変更するには、新しい型で新しい属性名を登録し、ワークフローがその名前に書き込むよう更新して、既存の実行が追いついたら新しい名前でフィルターします。同じ名前を削除して別の型で登録し直すと、以前の値は古い型のまま残ります。 diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/polyglot/php.md b/i18n/ja/docusaurus-plugin-content-docs/current/polyglot/php.md index ab9dc50023d..3aa35f3fb13 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/polyglot/php.md +++ b/i18n/ja/docusaurus-plugin-content-docs/current/polyglot/php.md @@ -200,7 +200,7 @@ PHP `^8.1`、Laravel ブリッジの下限、ワーカープロトコル `1.20` - **sticky 履歴サフィックス(3.14)。** ワーカーは `sticky_history_suffix` を示します。Server 3.5.0 以降では、実行の履歴をすでに保持しているワーカーは、キャッシュしたシーケンスより後のイベントだけを受け取ります。キャッシュした履歴に正確に続かないサフィックスは破棄され、完全な履歴を取得します。古い Server は引き続き完全な履歴を送ります。 - **スケジュールの起点(3.13)。** `WorkflowContext::scheduleOrigin()` は、実行を開始したスケジュール発火のスケジュール ID、発生時刻、トリガー番号を返します。通常の開始では `null` です。リプレイでも同じ値になります。Server 3.5.0 以降、continue-as-new で続く実行はスケジュールの起点を保持します。 -- **アクティビティ継続(3.12)。** Server が `activity_workflow_continuation` を示す場合(ネイティブ Server 3.4.0 以降)、`Worker` コンストラクターに `enableActivityContinuation: true` を渡すと、成功したアクティビティ結果と次のワークフローコマンドをまとめて送信します。デフォルトは `false` です。有効にする場合は 3.12.1 以降を使い、Server をダウングレードしたり古い Server ノードを追加したりする前に、それらのワーカーをドレインまたは無効化してください。 +- **アクティビティ継続(3.12)。** Server が `activity_workflow_continuation` を示す場合(ネイティブ Server 3.4.0 以降)、`Worker` コンストラクターに `enableActivityContinuation: true` を渡すと、成功したアクティビティ結果と次のワークフローコマンドをまとめて送信します。デフォルトは `false` です。現在、有効にするとスループットが低下します。負荷をかけたベンチマークでは、有効にするとワークフローが 24〜49% 遅くなり、データベーストランザクションが 2 倍になりました([測定](https://github.com/durable-workflow/server/issues/1078))。有効にする場合は 3.12.1 以降を使い、Server をダウングレードしたり古い Server ノードを追加したりする前に、それらのワーカーをドレインまたは無効化してください。 完全な一覧は [3.14.0 の変更履歴](https://github.com/durable-workflow/sdk-php/blob/3.14.0/CHANGELOG.md) を参照してください。 diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/testing.md b/i18n/ja/docusaurus-plugin-content-docs/current/testing.md index 8e3e2286333..70443237428 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/testing.md +++ b/i18n/ja/docusaurus-plugin-content-docs/current/testing.md @@ -354,7 +354,7 @@ public function testReturnExistingActiveStart(): void ### 履歴の使用量上限をテストする {#testing-history-budget} -`HistoryBudget` フィールド(`history_event_count`、`history_size_bytes`、`continue_as_new_recommended`)は、実行概要の投影と `RunDetailView` から利用できます。ワークフローコードでは、`Workflow` 基底クラスが `$this->historyLength()`、`$this->historySize()`、`$this->shouldContinueAsNew()` として公開します。 +`HistoryBudget` フィールド(`history_event_count`、`history_size_bytes`、`continue_as_new_recommended`)は、実行概要の投影と `RunDetailView` から利用できます。ワークフローコードでは、`Workflow` 基底クラスが `$this->historyLength()`、`$this->historySize()`、`$this->shouldContinueAsNew()` として公開します。ループ内では、どのリプレイでも同じ結果を返す `$this->shouldContinueAsNewAtStep()`(Workflow 2.26 以降)を使ってください。 ```php use Workflow\V2\Workflow; @@ -366,7 +366,7 @@ final class LongRunningWorkflow extends Workflow while (true) { // ... process work ... - if ($this->shouldContinueAsNew()) { + if ($this->shouldContinueAsNewAtStep()) { Workflow::continueAsNew($this->carryForwardState()); } } diff --git a/i18n/ja/source-hashes.json b/i18n/ja/source-hashes.json index aaa9e3d33f5..29802b30c7c 100644 --- a/i18n/ja/source-hashes.json +++ b/i18n/ja/source-hashes.json @@ -4,7 +4,7 @@ "ai-agent-workflow-engine.md": "28016466b179adbabdff6467ce351100c9bee48529a8bec9df7ec22c8d786d4d", "ai-assisted-development.md": "b246bb60585fb7a69bc534978f470f3f16e899e1f8f203ba0847d2d11b8a1ec3", "capabilities.md": "d9a2bbc0d04adf8cb3f4c7f42d779a43aafab60791210305e7e476c0499528fc", - "compatibility.md": "567310faf420fbd5229c5eef69721e8b7d09f033333cbaec21b72acaf81b6690", + "compatibility.md": "ad5c8519be03ae1e7b6e5e03b05a886862fd67c603b241ecb5baf2be5cd59610", "configuration/customization-matrix.md": "3d115863eaee7852b541bcd01615f424cc19c5847c7cd7d75e5ae63bc3f5cc78", "configuration/database-connection.md": "cc83ae77133236309506fa44d39bfd0c939c32a6154c0bd6099bc64c83bdaec9", "configuration/ensuring-same-server.md": "6c665f37cc198c7b1a775a60a94aab5ff4e55383385e76f1834c7840559b512a", @@ -24,18 +24,18 @@ "defining-workflows/activities.md": "05b46f73477a0bbd5f21d17ac37def8a8eac53f1e629155805c98cc46e75b418", "defining-workflows/passing-data.md": "c5d36126b0b15f1780119f6418e8bbe5a63e03353be5a0bb69385206ef0ad635", "defining-workflows/starting-workflows.md": "722b80454b577b0715ff50db70c7cda2cd02c34c505dd1219a83307852d325a4", - "defining-workflows/workflow-api.md": "a6150e75302323b49f350159ce3568a51a19701bb81829915615f754592ee79c", + "defining-workflows/workflow-api.md": "3c13894c1fdbe77bb1379c62bbdb0ef213c81f1cba5b477d45402dcc7fe87237", "defining-workflows/workflow-id.md": "ca3b43253a748b27dca1af9f82fcf8c4c133e14f13e1b82eaa1ca2ed0996d4bf", "defining-workflows/workflow-status.md": "8e8cb27ff44c890d489d89bf166375acfdfaecabd990a2235e106fab1592d529", "defining-workflows/workflows.md": "f467bc73de32aa5d722c61ce085065460382ae7dd44cea4625847d9fcdc4c97c", "deployment.md": "6aa439b1ebfdc2affccaf6fe6fff7519776a4ffcad8d3cb5956b665e7c97257f", - "failures-and-recovery.md": "598b538e2bcb6a40a4f2d4c0c462705bab30ef96767144f6590c2cc93b68a98a", + "failures-and-recovery.md": "4209521a8783939d458658a7afea64124c34571080c97feb2868a273db88db3e", "features/activity-execution-model.md": "e8c37520ae46a7efb30438f4fc06bf893c1df430cb1f92c48963697adaf09082", "features/cancel-and-terminate.md": "cedd1e6c51dfa551e00edc1d39739ff1f67d558d2a0be92143f478cb6111536b", - "features/child-workflows.md": "57016591fb8816aed7b077e204f1c80f9c6a8dff7501bc00a141c41a4607306b", + "features/child-workflows.md": "278b634b8b48b94203309cdba27d6116897a2919cab19628add8cd85dadb08d3", "features/concurrency.md": "a7a3eb2274f7b14faf722494569b7663c07ab48afdf2e9225e58914b84cacbb4", "features/condition-waits.md": "451261eda990c9591a0db69839d872184b5c64da6b537a582133095b8d4b599e", - "features/continue-as-new.md": "50c79f317155e052a3f2f37d198a71bdfc496a454905293f40cf09d73138f25b", + "features/continue-as-new.md": "a5309192c685abeb5295071d423824ae2287e68d247a6661f18d3ab21f9bdc9c", "features/events.md": "c466df05908748489226a3d1410c9203cf6f2986a4bb7539db1c5f82715abc7b", "features/external-payload-storage.md": "acc312fa2f50a43c96e1d235439124d28a7048f0bf3abac34319467fcbf7e898", "features/heartbeats.md": "4fce9636d68c89f29f259d52e463cd67eccf0bc55ad4d53338ed03329892b365", @@ -45,7 +45,7 @@ "features/queries.md": "c66dd9542a062edd8158a46cebc9f1bf926aaf3599dca4a3122bd9860df6e2a2", "features/sagas.md": "046ba5661ccb5ac71a236356d243b021d9830123e3798afce491118434e83820", "features/schedules.md": "40d30b2767e7ed043e2b0c7180915c256accea3e7a3401c38d1bf75bfe1c2213", - "features/search-attributes.md": "567d89858cd82e86672b210154001a272b17a5f87e13dbfa7de1b8e093d615b8", + "features/search-attributes.md": "bb66d83f64e0098354d86ac237e6867b9819098044101ba9a60a6a00a3961dd1", "features/service-operations.md": "912131c0a8ef393040a933fb4a66e68abcb9d475a3ebd47c85287d4032f45a0e", "features/side-effects.md": "abdccab8d6fc1a12b3eff8a4ccc58730ac36f523559b4ad89c5c2a8d201a3b86", "features/signal+timer.md": "a05fc480544fa71f6c9b215ad3417f71b8475dd81f9de8ee18d7a3b69ac33a23", @@ -80,7 +80,7 @@ "polyglot/invocable-carrier.md": "d32d8b5c7c33204b342f977e0af734166d91e96073db1a49ccb4d414a6d67380", "polyglot/invocable-php-handler.md": "3b678eb1d69fe32dfcfdc05d36b33e49e01b79d7216bd784f6a61a6f1c3c3a13", "polyglot/namespace-auth-workers.md": "2b4078ceb74b849f12cb1975b410ff8e7266cd4345f6cf1d4dd906db12460ffb", - "polyglot/php.md": "04f7eeebf842bbcd2f278f96ee21fbbf4f97d424a27e717d65e1c73273bce095", + "polyglot/php.md": "309e83622754b9d9abc65807280f2dab175a009054a001456ef1316776f11101", "polyglot/polling-patterns.md": "30875099a23731c6c471b481a771378acc6ff57eed2fda4405a509057534c989", "polyglot/portable-worker-affinity.md": "40973c6a31a76845b4f95e9a505e68ad76abd5174bbdccf37993cdebc8904959", "polyglot/prerelease-history-migration.md": "a57f05f492228a8a67791f9152648a1e5f80856325b78777cf63b6ef49b7413c", @@ -105,6 +105,6 @@ "sdk-neutrality.md": "7b0714c123ade4904591870fc20e9a797da1e5485b2a6c87ca3eaa00c5de6ed6", "sponsors.md": "e85e14375743ca8fa50e3a48f894b160e28272573aa88480064f74010ebee98a", "support.md": "706807b3902599dda6080f632ec1f893017ea18bbe9585f533dcdbd6d85f4621", - "testing.md": "250bc7dfd46f99eaeb392b329947813b064bda72026645198e3aefc80043a813", + "testing.md": "176abf226936c7711c2df523fb8a94e92fcf62e6f804d99f2e32b9135f626547", "waterline-operator-api.md": "2aca03b2c14100060b40be0bb033a82525ba924908834e9060ec746ead26f36d" } diff --git a/i18n/pt-BR/docusaurus-plugin-content-docs/current/compatibility.md b/i18n/pt-BR/docusaurus-plugin-content-docs/current/compatibility.md index 5fde803a21a..a399280184f 100644 --- a/i18n/pt-BR/docusaurus-plugin-content-docs/current/compatibility.md +++ b/i18n/pt-BR/docusaurus-plugin-content-docs/current/compatibility.md @@ -101,12 +101,12 @@ O pacote embutido e o SDK de modo de serviço têm contratos separados. | Linha do pacote | PHP | Laravel | | --- | --- | --- | -| Workflow embutido 2.24 atual | PHP 8.2+ da linha 8.x; PHP 8.3+ para Laravel 13 | `^12.69.0` ou `^13.30.0` | +| Workflow embutido 2.26 atual | PHP 8.2+ da linha 8.x; PHP 8.3+ para Laravel 13 | `^12.69.0` ou `^13.30.0` | | Workflow embutido 2.20.5 | PHP `^8.1`, respeitando o mínimo do framework | `^10.50.4`, `^11.56.1`, `^12.69.0` ou `^13.30.0` | | SDK PHP 3.14 publicado | SDK básico PHP `^8.1`; a ponte Laravel exige PHP `^8.2`, e PHP 8.3+ para Laravel 13 | `^12.69.0` ou `^13.30.0` | | SDK PHP 3.9.5 | SDK básico PHP `^8.1`; a ponte Laravel também segue o mínimo do framework | `^10.50.4`, `^11.56.1`, `^12.69.0` ou `^13.30.0` | -As autoridades são o [contrato embutido publicado](https://github.com/durable-workflow/workflow/blob/2.24.0/resources/laravel-embedded-upgrade-contract.json) +As autoridades são o [contrato embutido publicado](https://github.com/durable-workflow/workflow/blob/2.26.0/resources/laravel-embedded-upgrade-contract.json) e o `composer.json` de cada versão. A versão embutida atual foi verificada com Laravel 12/PHP 8.2–8.4 e Laravel 13/PHP 8.3–8.4. Ela remove suporte a PHP 8.1 e Laravel 10/11. Isso preserva o [guia histórico do v1 estável](/docs/1.x/installation/) @@ -147,6 +147,16 @@ O Workflow 2.23 e o 2.24 mantêm os pisos de suporte do 2.21 e o protocolo de wo Veja as notas de versão do [2.23.0](https://github.com/durable-workflow/workflow/releases/tag/2.23.0), [2.23.1](https://github.com/durable-workflow/workflow/releases/tag/2.23.1), [2.23.2](https://github.com/durable-workflow/workflow/releases/tag/2.23.2) e [2.24.0](https://github.com/durable-workflow/workflow/releases/tag/2.24.0). +O Workflow 2.25 e o 2.26 mantêm os pisos de suporte do 2.21 e o protocolo de workers embutido `1.22`. O 2.25 não adiciona migração de banco de dados. O 2.26 adiciona uma, então execute `php artisan migrate` ao atualizar. Ela cria a tabela `workflow_child_supervisions`. Mudanças para verificar antes de atualizar: + +- A partir do 2.26, um pai que continua como novo enquanto filhos que ele iniciou ainda estão abertos os transfere para a nova execução. A execução final da cadeia aplica a política de encerramento do pai a eles, e um filho que falha ainda recebe novas tentativas sob a política de novas tentativas registrada. Veja [Continuar como novo e filhos abertos](./features/child-workflows.md#continue-as-new-and-open-children). +- A partir do 2.26, as migrações de versões anteriores que preenchem linhas existentes (`2026_07_13`, `2026_09_24`, `2026_09_29` e `2026_10_11`) não bloqueiam mais a tabela durante todo o preenchimento retroativo. Elas adicionam a coluna primeiro, preenchem as linhas em lotes pequenos e depois criam seus índices sem bloquear gravações. Se uma delas for interrompida, execute `php artisan migrate` de novo. Instalações que já as executaram não são afetadas. +- A partir do 2.26, o redrive reutiliza um workflow filho que foi concluído antes da falha. Versões anteriores à 2.26 reproduzem essa sucessora com um horário de workflow diferente depois do filho reutilizado, então mantenha os workers na 2.26 ou posterior quando existir uma. Veja [Redrive de uma execução com falha](./failures-and-recovery.md#redrive). +- A partir do 2.26, `historyBudgetAtStep()` e `shouldContinueAsNewAtStep()` leem o limite do histórico da mesma forma em todo replay. Use-os em loops. Veja [Limites do histórico](./features/continue-as-new.md#history-budget). +- A partir do 2.25, ultrapassar um limite fixo de memo ou de atributo de busca lança `StructuralLimitExceededException` em vez de `InvalidArgumentException`, e o padrão de `memo_size_bytes` é 65.536. Veja [Limites estruturais](./constraints/structural-limits.md). + +Veja as notas de versão do [2.25.0](https://github.com/durable-workflow/workflow/releases/tag/2.25.0) e do [2.26.0](https://github.com/durable-workflow/workflow/releases/tag/2.26.0). + ## Níveis de estabilidade {#stability-levels} Cada interface pública do Durable Workflow tem exatamente um destes níveis. diff --git a/i18n/pt-BR/docusaurus-plugin-content-docs/current/defining-workflows/workflow-api.md b/i18n/pt-BR/docusaurus-plugin-content-docs/current/defining-workflows/workflow-api.md index 9a86adcf171..1fae49e00d2 100644 --- a/i18n/pt-BR/docusaurus-plugin-content-docs/current/defining-workflows/workflow-api.md +++ b/i18n/pt-BR/docusaurus-plugin-content-docs/current/defining-workflows/workflow-api.md @@ -55,6 +55,8 @@ abstract class Workflow public function historyLength(): int; public function historySize(): int; public function shouldContinueAsNew(): bool; + public function historyBudgetAtStep(): array; + public function shouldContinueAsNewAtStep(): bool; } ``` @@ -67,6 +69,8 @@ abstract class Workflow | `historyLength()` | O workflow precisa de uma indicação de orçamento de histórico baseada em contagem. | Contagem atual de eventos do histórico. | | `historySize()` | O workflow precisa de uma indicação de orçamento de histórico baseada em bytes. | Tamanho aproximado do histórico persistido em bytes. | | `shouldContinueAsNew()` | O workflow deve iniciar outra execução antes que o histórico fique caro. | `true` quando os orçamentos de histórico configurados recomendam essa troca. | +| `historyBudgetAtStep()` | O workflow lê o orçamento mais de uma vez em uma execução, por exemplo em um loop (Workflow 2.26+). | Contadores do orçamento no passo atual, iguais em todo replay. | +| `shouldContinueAsNewAtStep()` | Um loop decide se deve iniciar outra execução (Workflow 2.26+). | `true` quando o histórico anterior ao passo atual ultrapassa um orçamento configurado. | ## Comandos duráveis {#durable-commands} diff --git a/i18n/pt-BR/docusaurus-plugin-content-docs/current/failures-and-recovery.md b/i18n/pt-BR/docusaurus-plugin-content-docs/current/failures-and-recovery.md index afda9109b64..bf3e5bd1d82 100644 --- a/i18n/pt-BR/docusaurus-plugin-content-docs/current/failures-and-recovery.md +++ b/i18n/pt-BR/docusaurus-plugin-content-docs/current/failures-and-recovery.md @@ -119,6 +119,7 @@ A sucessora reproduz o código do workflow desde o início: - Um memo ou atributo de busca em que o código do workflow fez upsert antes do passo com falha é reutilizado na ordem dos passos, e a sucessora mantém os mesmos valores. - Uma espera de sinal (`await('name')`) que recebeu e aplicou o sinal é reutilizada com o valor do sinal. O sinal não é entregue de novo. - Um update que foi aceito, aplicado e concluído antes do passo com falha é registrado de novo na mesma posição. O replay executa o handler do update com os argumentos registrados, então o estado do workflow confere. O update não é entregue de novo. Um update rejeitado, e um que a falha fechou antes de ser executado, ficam de fora. +- No Workflow 2.26 e posteriores, uma chamada de workflow filho concluída antes do passo com falha retorna o resultado registrado. O filho não é iniciado de novo. A sucessora registra os eventos `ChildWorkflowScheduled`, `ChildRunStarted` e `ChildRunCompleted` da chamada e mantém a instância filha, a execução filha, o id de vínculo e o id de chamada originais, mas não recebe um vínculo de filho próprio. - `outbox()->sendReference()` e `inbox()->receive()` no código de workflow reutilizado retornam a mensagem que a execução com falha enviou ou consumiu. Eles não a enviam nem a consomem de novo. Um receive em replay cuja chamada original não encontrou nada lê o stream de novo. - No Workflow 2.20.2 e posteriores, mensagens de entrada do stream ainda pendentes na execução com falha passam para a sucessora. O Workflow 2.20.1 e anteriores as deixavam na execução com falha, então a sucessora nunca as recebia ([workflow#1013](https://github.com/durable-workflow/workflow/issues/1013)). - Se uma falha de atividade encerrou a execução, a chamada de atividade que falhou é agendada como uma nova execução de atividade, com a política de novas tentativas do código do workflow. As tentativas recomeçam. @@ -128,7 +129,7 @@ A sucessora reproduz o código do workflow desde o início: - A sucessora mantém o prazo de execução da execução com falha. O timeout de execução dela recomeça no redrive. - Cada passo reutilizado carrega `reused_from_run_id` e `reused_recorded_at`. Em um evento reutilizado de update ou de sinal, os dois sempre vêm em par. - Um sucessor que reutilizou passos pode passar por um novo redrive. Um payload de sinal ou de update reutilizado mantém em `workflow_run_id` a execução que o registrou primeiro, `reused_from_run_id` indica a execução de onde veio o redrive, e cada passo reutilizado mantém o horário em que foi executado pela primeira vez, então uma cadeia de redrives reutiliza cada passo uma única vez. -- No modo embedded, `Workflow::now()` na sucessora começa no horário de início da execução com falha. A reprodução usa `reused_recorded_at`, então `Workflow::now()` depois de um passo reutilizado corresponde ao horário da execução com falha. Um passo reutilizado por um segundo redrive mantém o horário em que foi executado pela primeira vez. +- No modo embedded, `Workflow::now()` na sucessora começa no horário de início da execução com falha. A reprodução usa `reused_recorded_at`, então `Workflow::now()` depois de um passo reutilizado corresponde ao horário da execução com falha. Depois de uma chamada de workflow filho reutilizada, esse é o horário em que o filho terminou pela primeira vez. Um passo reutilizado por um segundo redrive mantém o horário em que foi executado pela primeira vez. ### Solicitar um redrive {#request-a-redrive} @@ -184,11 +185,12 @@ O redrive aceita uma execução com falha quando tudo isto é verdadeiro: - A execução é a execução atual da instância. - A execução falhou porque uma falha de atividade chegou ao código do workflow e não foi capturada, ou porque o código do workflow lançou uma exceção ou um limite estrutural a interrompeu. Uma execução que falhou em um timeout do workflow é recusada. -- Cada passo antes do passo com falha é uma atividade concluída, um efeito colateral, um marcador de versão, um `timer()` que disparou, um upsert de memo ou de atributo de busca, uma espera de sinal que recebeu e aplicou o sinal, ou um update que foi aceito, aplicado e concluído com os mesmos argumentos. Um update rejeitado, e um que a falha fechou antes de ser executado, são permitidos e ficam de fora. Payloads de atividades, de efeitos colaterais, de sinais e de updates precisam estar armazenados inline. Um payload no armazenamento externo de payloads é recusado. +- Cada passo antes do passo com falha é uma atividade concluída, um efeito colateral, um marcador de versão, um `timer()` que disparou, um upsert de memo ou de atributo de busca, uma espera de sinal que recebeu e aplicou o sinal, um update que foi aceito, aplicado e concluído com os mesmos argumentos ou, no Workflow 2.26 e posteriores, uma chamada de workflow filho que foi concluída. Um update rejeitado, e um que a falha fechou antes de ser executado, são permitidos e ficam de fora. Payloads de atividades, de efeitos colaterais, de sinais, de updates e de resultados de filhos precisam estar armazenados inline. Um payload no armazenamento externo de payloads é recusado. - A definição do workflow corresponde à impressão digital registrada no início da execução, ou você passou `allow_definition_change` e o código corrigido reproduz os passos concluídos. Uma falha no código do workflow com a mesma definição é recusada. - O prazo de execução não venceu. -- A execução não tem workflow pai, nem workflows filhos, nem atividades locais, e a entrada dela está armazenada em linha. -- Se um worker de serviço iniciou a execução, os passos antes da falha são apenas atividades, efeitos colaterais, marcadores de versão e timers disparados. Upserts de memo e de atributo de busca, esperas de sinal e updates aplicados são recusados em execuções de serviço. +- A execução não tem workflow pai nem atividades locais, e a entrada dela está armazenada em linha. Antes do Workflow 2.26, ela também não tem workflows filhos. Uma execução que é ela própria filha nunca passa por redrive, porque o pai já registrou o resultado do filho. +- Cada chamada de workflow filho antes do passo com falha foi concluída por conta própria, fora de um grupo paralelo ou escopo de cancelamento, sem nova tentativa nem continue-as-new. +- Se um worker de serviço iniciou a execução, os passos antes da falha são apenas atividades, efeitos colaterais, marcadores de versão e timers disparados. Upserts de memo e de atributo de busca, esperas de sinal, updates aplicados e chamadas de workflow filho concluídas são recusados em execuções de serviço. Uma recusa indica a primeira regra que não foi atendida: @@ -198,7 +200,12 @@ Uma recusa indica a primeira regra que não foi atendida: | `source_run_not_current` | Existe uma execução mais recente da instância. | | `unrecorded_failure_boundary` | A falha da execução não tem um passo registrado, como uma falha no código do workflow registrada por uma versão anterior à 2.19.0. | | `workflow_code_failure_requires_corrected_definition` | O código do workflow lançou uma exceção e a definição não mudou, então o mesmo código lançaria a exceção de novo. | -| `unsupported_history` | O histórico antes da falha tem um passo que o redrive não consegue reutilizar, como um workflow filho ou um timer cancelado. | +| `unsupported_history` | O histórico antes da falha tem um passo que o redrive não consegue reutilizar, como um timer cancelado. Antes do Workflow 2.26, qualquer workflow filho. | +| `unsupported_open_child` | Uma chamada de workflow filho antes da falha nunca foi fechada. Workflow 2.26 e posteriores. | +| `unsupported_child_outcome` | Um workflow filho antes da falha falhou, foi cancelado ou foi terminado. Workflow 2.26 e posteriores. | +| `unsupported_child_workflow` | Uma chamada de workflow filho está em um grupo paralelo ou escopo de cancelamento, recebeu nova tentativa ou continuou como nova, ou seus eventos não indicam uma única chamada de filho. Workflow 2.26 e posteriores. | +| `external_child_result_not_supported` | O resultado de um workflow filho concluído está no armazenamento externo de payloads. Workflow 2.26 e posteriores. | +| `unavailable_child_result` | O resultado de um workflow filho concluído não pode ser decodificado. Workflow 2.26 e posteriores. | | `unsupported_local_activity` | O histórico contém uma atividade local. | | `unsupported_timer` | O histórico contém um timeout de condição ou de sinal, um timer de limpeza de cancelamento, ou um timer dentro de um escopo de cancelamento ou de um grupo paralelo. | | `incomplete_timer_step` | Um passo de timer não tem os dois eventos, de agendamento e de disparo. | @@ -225,7 +232,7 @@ Uma recusa indica a primeira regra que não foi atendida: | `definition_incompatible_with_prefix` | O código corrigido não consegue reproduzir os passos concluídos. `definition_mismatch` indica o primeiro passo que difere. | | `definition_check_over_budget` | O histórico concluído é maior que o orçamento de histórico permitido pela verificação de reprodução. | | `definition_change_requires_replay_check` | Um worker de serviço iniciou a execução, então o redrive não consegue verificar uma definição alterada. | -| `service_redrive_history_not_qualified` | Um worker de serviço iniciou a execução, e os passos antes da falha incluem um upsert de memo, um upsert de atributo de busca, uma espera de sinal ou um update aplicado. O redrive recusa esses passos em execuções de serviço até poder verificar, para cada runtime de SDK, se ele consegue reproduzi-los no replay. | +| `service_redrive_history_not_qualified` | Um worker de serviço iniciou a execução, e os passos antes da falha incluem um upsert de memo, um upsert de atributo de busca, uma espera de sinal, um update aplicado ou uma chamada de workflow filho concluída. O redrive recusa esses passos em execuções de serviço até poder verificar, para cada runtime de SDK, se ele consegue reproduzi-los no replay. | | `request_id_already_used` | O `request_id` já foi usado em outro redrive da instância. | | `already_redriven` | Informado pelos detalhes da execução e por `describe()` para uma execução que já passou por redrive. Uma solicitação de redrive para ela retorna o sucessor existente. | | `invalid_request_id` | O `request_id` tem mais de 191 caracteres. | @@ -247,6 +254,8 @@ No Workflow 2.20.0 e posteriores, os detalhes da execução e `describe()` infor ### Versões anteriores e o Server nativo {#redrive-earlier-releases} +Versões do Workflow anteriores à 2.26.0 recusam qualquer workflow filho no histórico com `unsupported_history`. Elas ignoram `reused_recorded_at` nos eventos de workflow filho, então uma sucessora da 2.26.0 que reutilizou uma chamada de filho pode ser reproduzida nelas com um horário de workflow diferente, e prazos diferentes, depois da chamada. Elas também recusam um novo redrive dela. Depois que existir uma sucessora assim, mantenha os workers na 2.26.0 ou posterior, ou confirme que nenhum histórico assim pode ser reproduzido, antes de fazer rollback. + O Workflow 2.20.0 não recusa nada que o 2.20.1 aceite. No 2.20.0, `outbox()->sendReference()` no código de workflow reutilizado envia de novo, e um `inbox()->receive()` em replay pode retornar outras mensagens ou nenhuma, ou consumir uma mensagem mais nova ([workflow#1010](https://github.com/durable-workflow/workflow/issues/1010)). O Workflow 2.19.0 recusa um update aplicado (`unsupported_history`). Ele também recusa o redrive de um sucessor que reutilizou um update (`unsupported_history`) ou uma espera de sinal (`mismatched_signal_receipt`). Os detalhes da execução e `describe()` mostram os vínculos de redrive como fallback de diagnóstico. diff --git a/i18n/pt-BR/docusaurus-plugin-content-docs/current/features/child-workflows.md b/i18n/pt-BR/docusaurus-plugin-content-docs/current/features/child-workflows.md index a11092da02c..1d359ba2fe6 100644 --- a/i18n/pt-BR/docusaurus-plugin-content-docs/current/features/child-workflows.md +++ b/i18n/pt-BR/docusaurus-plugin-content-docs/current/features/child-workflows.md @@ -200,7 +200,7 @@ $results = all([ - Quando a execução pai encerra por qualquer motivo, o mecanismo consulta vínculos abertos de filhos com uma política diferente de abandonar e envia o comando adequado (solicitar cancelamento cooperativo, cancelar ou terminar) a cada filho aberto. - Se o filho já tiver encerrado quando a política for aplicada, nenhuma ação ocorre: o comando é ignorado silenciosamente. - A aplicação da política é de melhor esforço: se um comando do filho for rejeitado, por exemplo porque ele já está terminal, o encerramento do pai não é afetado. Quando a aplicação tem sucesso, um evento `ParentClosePolicyApplied` é registrado no histórico da execução pai. Quando falha, registra-se `ParentClosePolicyFailed`, permitindo aos operadores distinguir a aplicação bem-sucedida de falhas silenciosas. -- Continue-as-new **não** aciona a política de encerramento do pai, pois a instância de workflow permanece ativa sob uma nova execução. +- Continue-as-new **não** aciona a política de encerramento do pai, pois a instância de workflow permanece ativa sob uma nova execução. A partir do Workflow 2.26, a execução final da cadeia a aplica no lugar. Veja [Continuar como novo e filhos abertos](#continue-as-new-and-open-children). ### Matriz de resultados do pai {#parent-disposition-matrix} @@ -213,9 +213,21 @@ A política de encerramento do pai é acionada para todo resultado terminal do p | Tempo limite excedido | Sim | Aciona após o registro de `WorkflowTimedOut` em encerramentos por tempo limite de execução ou da cadeia de execuções. | | Cancelado | Sim | Aciona depois que o comando aceito `CancelRequested` encerra a execução pai. | | Terminado | Sim | Aciona depois que o comando aceito `TerminateRequested` encerra a execução pai. | -| Continue-as-new | Não | A instância de workflow permanece ativa sob a nova execução, por isso os vínculos existentes de filhos são redirecionados a ela, preservando a política original. | +| Continue-as-new | Não | A instância de workflow permanece ativa sob a nova execução. A partir do Workflow 2.26, a nova execução assume a supervisão dos filhos abertos, e a execução final da cadeia aplica a política deles. | | Reset | Não se aplica atualmente | O runtime v2 não expõe um comando independente de reset nem um resultado terminal de reset. Uma futura operação de reset ou reparo que encerre ou substitua uma execução pai deve definir se a titularidade dos filhos é transferida. Se a execução antiga se tornar terminal, deve aplicar a política de encerramento do pai antes de deixar de deter os filhos abertos. | +### Continuar como novo e filhos abertos {#continue-as-new-and-open-children} + +No Workflow 2.26 e posteriores, um pai que continua como novo enquanto filhos que ele iniciou ainda estão abertos os transfere para a nova execução, na mesma transação. Execuções embutidas e no modo de serviço se comportam da mesma forma: + +- Cada filho aberto recebe uma linha na tabela `workflow_child_supervisions`, que a migração do 2.26 cria. Um filho que já foi encerrado não é transferido. +- O vínculo do filho, a chamada do filho, a sequência, os prazos e a política de encerramento do pai permanecem como a execução inicial os registrou. Quando a nova execução continua como nova de novo, ela transfere os filhos de novo. +- Quando a execução final da cadeia é concluída, falha, excede o tempo limite, é cancelada ou é terminada, ela aplica a política de cada filho e registra `ParentClosePolicyApplied` ou `ParentClosePolicyFailed` no próprio histórico. `abandon` continua `abandon`. A execução anterior já encerrada não recebe histórico novo. +- A nova execução não tem referência para esses filhos, e os resultados deles não são entregues a ela. Passe tudo o que a próxima execução precisa nos argumentos de `continueAsNew()`. +- Um filho transferido que falha recebe novas tentativas sob a política de novas tentativas que a execução inicial registrou, com a mesma identidade de chamada de filho e a mesma contagem de tentativas, enquanto uma execução da cadeia ainda o supervisiona. O `WorkflowStarted` da execução de nova tentativa indica a execução inicial como pai, e a execução final da cadeia aplica a política de encerramento do pai à execução de nova tentativa. A falha é definitiva quando as tentativas se esgotam, quando a falha não permite nova tentativa ou quando a cadeia já foi encerrada. + +Antes do 2.26, esses filhos continuavam executando depois que a cadeia era encerrada e a política deles nunca era aplicada, e um filho que falhava depois que o pai continuava como novo não recebia novas tentativas. Veja as [notas de versão do 2.26.0](https://github.com/durable-workflow/workflow/releases/tag/2.26.0). + ### Quando usar cada política {#when-to-use-each-policy} **Abandonar** (padrão) é adequado quando filhos representam trabalho independente que deve concluir independentemente do destino do pai, como um workflow de notificação ou uma tarefa de limpeza que precisa terminar. diff --git a/i18n/pt-BR/docusaurus-plugin-content-docs/current/features/continue-as-new.md b/i18n/pt-BR/docusaurus-plugin-content-docs/current/features/continue-as-new.md index bf3f24d9b88..397f176db05 100644 --- a/i18n/pt-BR/docusaurus-plugin-content-docs/current/features/continue-as-new.md +++ b/i18n/pt-BR/docusaurus-plugin-content-docs/current/features/continue-as-new.md @@ -82,6 +82,10 @@ Loops de longa duração podem limitar o histórico por execução sem inventar O código do workflow pode observar o tamanho atual do histórico e um indicador de sugestão de continuar como novo por meio do contexto explícito do runtime. Isso permite que loops de longa duração façam a transferência deliberadamente antes de atingir os limites do histórico. +No Workflow 2.26 e posteriores, use `shouldContinueAsNewAtStep()` e `historyBudgetAtStep()`. Eles contam apenas o histórico registrado antes do passo atual do workflow, então a mesma linha retorna a mesma resposta em todo replay. Um loop que verifica o limite a cada iteração continua como novo uma única vez, na primeira iteração que ultrapassa o limite. + +Os métodos mais antigos leem todo o histórico atual. Dentro de um loop, uma iteração anterior pode ver um total posterior no replay e seguir um caminho diferente do que seguiu da primeira vez. Eles não mudaram, então execuções que já decidiram com eles continuam sendo reproduzidas. + ```php use function Workflow\V2\activity; use function Workflow\V2\continueAsNew; @@ -109,6 +113,8 @@ class PollingWorkflow extends Workflow | `$this->historyLength()` | `int` | Número de eventos de histórico na execução atual | | `$this->historySize()` | `int` | Tamanho total dos eventos de histórico em bytes | | `$this->shouldContinueAsNew()` | `bool` | `true` quando a execução excede o limite configurado de quantidade de eventos ou tamanho em bytes | +| `$this->historyBudgetAtStep()` | `array` | O limite no passo atual: `history_event_count`, `history_size_bytes`, `history_fan_out`, `continue_as_new_recommended`, `pressure`, `pressure_dimensions` e `observation` (`step_prefix.v1`). Workflow 2.26 e posteriores. | +| `$this->shouldContinueAsNewAtStep()` | `bool` | `continue_as_new_recommended` de `historyBudgetAtStep()`. Use-o em loops. Workflow 2.26 e posteriores. | ### Configuração {#configuration} @@ -124,7 +130,7 @@ Os limites para recomendar continuar como novo são configuráveis: ], ``` -`shouldContinueAsNew()` retorna `true` quando qualquer um dos limites é ultrapassado. Os resumos de execução também acompanham `history_event_count`, `history_size_bytes` e `continue_as_new_recommended`, para que o Waterline possa sinalizar execuções de longa duração nas visões da frota. +`shouldContinueAsNew()` e `shouldContinueAsNewAtStep()` retornam `true` quando qualquer um dos limites é ultrapassado. Os resumos de execução também acompanham `history_event_count`, `history_size_bytes` e `continue_as_new_recommended`, para que o Waterline possa sinalizar execuções de longa duração nas visões da frota. ## Transferência de metadados {#metadata-carry-forward} @@ -164,6 +170,8 @@ class PollingWorkflow extends Workflow } ``` +Um pai que continua como novo enquanto workflows filhos que ele iniciou ainda estão abertos os transfere para a nova execução. Veja [Continuar como novo e filhos abertos](./child-workflows.md#continue-as-new-and-open-children). + Para loops de longa duração com entrada humana ou de assistentes, prefira a fachada própria `$this->inbox()` / `$this->outbox()` de [Fluxos de mensagens](./message-streams.md). Mensagens do fluxo pendentes e a diff --git a/i18n/pt-BR/docusaurus-plugin-content-docs/current/features/search-attributes.md b/i18n/pt-BR/docusaurus-plugin-content-docs/current/features/search-attributes.md index bd249c440d1..41e505cb286 100644 --- a/i18n/pt-BR/docusaurus-plugin-content-docs/current/features/search-attributes.md +++ b/i18n/pt-BR/docusaurus-plugin-content-docs/current/features/search-attributes.md @@ -105,7 +105,7 @@ No Server, você pode registrar um atributo de busca com um tipo por meio de `PO O registro restringe apenas as chaves que você registra. A partir do Server nativo 3.5.0, uma chave não registrada continua sendo aceita e seu tipo é inferido, como em um namespace sem atributos registrados. Registrar um atributo não quebra workflows em execução que fazem upsert de outras chaves. PHP Server 2.x e o Server nativo anterior à 3.5.0 recusam toda chave não registrada assim que qualquer atributo é registrado, então, nessas versões, registre todas as chaves que seus workflows usam antes de registrar a primeira. -Excluir um registro encerra a verificação dessa chave. Os valores armazenados e os workflows em execução não mudam, e upserts posteriores da chave voltam a ser inferidos. +Excluir um registro encerra a verificação dessa chave. Os valores armazenados e os workflows em execução não mudam, e upserts posteriores da chave voltam a ser inferidos. No Server nativo, uma consulta de lista que filtra por uma chave não registrada, inclusive uma cujo registro você excluiu, é recusada porque a chave não está definida no namespace. Para mudar o tipo de um atributo, registre um novo nome de atributo com o novo tipo, atualize seus workflows para gravá-lo e filtre pelo novo nome quando as execuções existentes estiverem em dia. Excluir e registrar de novo o mesmo nome com outro tipo deixa os valores anteriores no tipo antigo. diff --git a/i18n/pt-BR/docusaurus-plugin-content-docs/current/polyglot/php.md b/i18n/pt-BR/docusaurus-plugin-content-docs/current/polyglot/php.md index 13d9e23a673..a8bcca1210c 100644 --- a/i18n/pt-BR/docusaurus-plugin-content-docs/current/polyglot/php.md +++ b/i18n/pt-BR/docusaurus-plugin-content-docs/current/polyglot/php.md @@ -307,7 +307,7 @@ Novidades destas versões: - **Sufixos de histórico sticky (3.14).** Os workers anunciam `sticky_history_suffix`. No Server 3.5.0 ou posterior, um worker que já tem o histórico de uma execução recebe só os eventos após a sequência que guardou em cache. Um sufixo que não continua exatamente o histórico em cache é descartado e o histórico completo é buscado. Servers mais antigos continuam enviando o histórico completo. - **Origem do schedule (3.13).** `WorkflowContext::scheduleOrigin()` retorna o id do schedule, o horário da ocorrência e o número do disparo que iniciou a execução, ou `null` em um início comum. O valor é o mesmo no replay. A partir do Server 3.5.0, uma execução que continua como nova mantém sua origem de schedule. -- **Continuações de atividade (3.12).** Passe `enableActivityContinuation: true` ao construtor de `Worker` para enviar os próximos comandos do workflow junto com um resultado de atividade bem-sucedido quando o Server anuncia `activity_workflow_continuation` (Server native 3.4.0 ou posterior). O padrão é `false`. Use a 3.12.1 ou posterior se ativar, e esvazie ou desative esses workers antes de rebaixar o Server ou adicionar nós de Server mais antigos. +- **Continuações de atividade (3.12).** Passe `enableActivityContinuation: true` ao construtor de `Worker` para enviar os próximos comandos do workflow junto com um resultado de atividade bem-sucedido quando o Server anuncia `activity_workflow_continuation` (Server native 3.4.0 ou posterior). O padrão é `false`. Ativá-la hoje custa vazão: no nosso benchmark sob carga, os workflows ficaram 24–49% mais lentos com ela ativada e usaram o dobro de transações de banco de dados ([medição](https://github.com/durable-workflow/server/issues/1078)). Use a 3.12.1 ou posterior se ativar, e esvazie ou desative esses workers antes de rebaixar o Server ou adicionar nós de Server mais antigos. Veja o [changelog da 3.14.0](https://github.com/durable-workflow/sdk-php/blob/3.14.0/CHANGELOG.md) para a lista completa. 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 d24a86dd133..ac52d04e091 100644 --- a/i18n/pt-BR/docusaurus-plugin-content-docs/current/testing.md +++ b/i18n/pt-BR/docusaurus-plugin-content-docs/current/testing.md @@ -357,7 +357,7 @@ As duas políticas registram comandos e eventos de histórico duráveis. Portant ### Testando o orçamento de histórico {#testing-history-budget} -Os campos de `HistoryBudget` (`history_event_count`, `history_size_bytes`, `continue_as_new_recommended`) aparecem na projeção de resumo da execução e estão disponíveis por meio de `RunDetailView`. No código do workflow, a classe base `Workflow` os expõe como `$this->historyLength()`, `$this->historySize()` e `$this->shouldContinueAsNew()`: +Os campos de `HistoryBudget` (`history_event_count`, `history_size_bytes`, `continue_as_new_recommended`) aparecem na projeção de resumo da execução e estão disponíveis por meio de `RunDetailView`. No código do workflow, a classe base `Workflow` os expõe como `$this->historyLength()`, `$this->historySize()` e `$this->shouldContinueAsNew()`. Dentro de um loop, use `$this->shouldContinueAsNewAtStep()` (Workflow 2.26 e posteriores), que dá a mesma resposta em todo replay: ```php use Workflow\V2\Workflow; @@ -369,7 +369,7 @@ final class LongRunningWorkflow extends Workflow while (true) { // ... process work ... - if ($this->shouldContinueAsNew()) { + if ($this->shouldContinueAsNewAtStep()) { Workflow::continueAsNew($this->carryForwardState()); } } diff --git a/i18n/pt-BR/source-hashes.json b/i18n/pt-BR/source-hashes.json index aaa9e3d33f5..29802b30c7c 100644 --- a/i18n/pt-BR/source-hashes.json +++ b/i18n/pt-BR/source-hashes.json @@ -4,7 +4,7 @@ "ai-agent-workflow-engine.md": "28016466b179adbabdff6467ce351100c9bee48529a8bec9df7ec22c8d786d4d", "ai-assisted-development.md": "b246bb60585fb7a69bc534978f470f3f16e899e1f8f203ba0847d2d11b8a1ec3", "capabilities.md": "d9a2bbc0d04adf8cb3f4c7f42d779a43aafab60791210305e7e476c0499528fc", - "compatibility.md": "567310faf420fbd5229c5eef69721e8b7d09f033333cbaec21b72acaf81b6690", + "compatibility.md": "ad5c8519be03ae1e7b6e5e03b05a886862fd67c603b241ecb5baf2be5cd59610", "configuration/customization-matrix.md": "3d115863eaee7852b541bcd01615f424cc19c5847c7cd7d75e5ae63bc3f5cc78", "configuration/database-connection.md": "cc83ae77133236309506fa44d39bfd0c939c32a6154c0bd6099bc64c83bdaec9", "configuration/ensuring-same-server.md": "6c665f37cc198c7b1a775a60a94aab5ff4e55383385e76f1834c7840559b512a", @@ -24,18 +24,18 @@ "defining-workflows/activities.md": "05b46f73477a0bbd5f21d17ac37def8a8eac53f1e629155805c98cc46e75b418", "defining-workflows/passing-data.md": "c5d36126b0b15f1780119f6418e8bbe5a63e03353be5a0bb69385206ef0ad635", "defining-workflows/starting-workflows.md": "722b80454b577b0715ff50db70c7cda2cd02c34c505dd1219a83307852d325a4", - "defining-workflows/workflow-api.md": "a6150e75302323b49f350159ce3568a51a19701bb81829915615f754592ee79c", + "defining-workflows/workflow-api.md": "3c13894c1fdbe77bb1379c62bbdb0ef213c81f1cba5b477d45402dcc7fe87237", "defining-workflows/workflow-id.md": "ca3b43253a748b27dca1af9f82fcf8c4c133e14f13e1b82eaa1ca2ed0996d4bf", "defining-workflows/workflow-status.md": "8e8cb27ff44c890d489d89bf166375acfdfaecabd990a2235e106fab1592d529", "defining-workflows/workflows.md": "f467bc73de32aa5d722c61ce085065460382ae7dd44cea4625847d9fcdc4c97c", "deployment.md": "6aa439b1ebfdc2affccaf6fe6fff7519776a4ffcad8d3cb5956b665e7c97257f", - "failures-and-recovery.md": "598b538e2bcb6a40a4f2d4c0c462705bab30ef96767144f6590c2cc93b68a98a", + "failures-and-recovery.md": "4209521a8783939d458658a7afea64124c34571080c97feb2868a273db88db3e", "features/activity-execution-model.md": "e8c37520ae46a7efb30438f4fc06bf893c1df430cb1f92c48963697adaf09082", "features/cancel-and-terminate.md": "cedd1e6c51dfa551e00edc1d39739ff1f67d558d2a0be92143f478cb6111536b", - "features/child-workflows.md": "57016591fb8816aed7b077e204f1c80f9c6a8dff7501bc00a141c41a4607306b", + "features/child-workflows.md": "278b634b8b48b94203309cdba27d6116897a2919cab19628add8cd85dadb08d3", "features/concurrency.md": "a7a3eb2274f7b14faf722494569b7663c07ab48afdf2e9225e58914b84cacbb4", "features/condition-waits.md": "451261eda990c9591a0db69839d872184b5c64da6b537a582133095b8d4b599e", - "features/continue-as-new.md": "50c79f317155e052a3f2f37d198a71bdfc496a454905293f40cf09d73138f25b", + "features/continue-as-new.md": "a5309192c685abeb5295071d423824ae2287e68d247a6661f18d3ab21f9bdc9c", "features/events.md": "c466df05908748489226a3d1410c9203cf6f2986a4bb7539db1c5f82715abc7b", "features/external-payload-storage.md": "acc312fa2f50a43c96e1d235439124d28a7048f0bf3abac34319467fcbf7e898", "features/heartbeats.md": "4fce9636d68c89f29f259d52e463cd67eccf0bc55ad4d53338ed03329892b365", @@ -45,7 +45,7 @@ "features/queries.md": "c66dd9542a062edd8158a46cebc9f1bf926aaf3599dca4a3122bd9860df6e2a2", "features/sagas.md": "046ba5661ccb5ac71a236356d243b021d9830123e3798afce491118434e83820", "features/schedules.md": "40d30b2767e7ed043e2b0c7180915c256accea3e7a3401c38d1bf75bfe1c2213", - "features/search-attributes.md": "567d89858cd82e86672b210154001a272b17a5f87e13dbfa7de1b8e093d615b8", + "features/search-attributes.md": "bb66d83f64e0098354d86ac237e6867b9819098044101ba9a60a6a00a3961dd1", "features/service-operations.md": "912131c0a8ef393040a933fb4a66e68abcb9d475a3ebd47c85287d4032f45a0e", "features/side-effects.md": "abdccab8d6fc1a12b3eff8a4ccc58730ac36f523559b4ad89c5c2a8d201a3b86", "features/signal+timer.md": "a05fc480544fa71f6c9b215ad3417f71b8475dd81f9de8ee18d7a3b69ac33a23", @@ -80,7 +80,7 @@ "polyglot/invocable-carrier.md": "d32d8b5c7c33204b342f977e0af734166d91e96073db1a49ccb4d414a6d67380", "polyglot/invocable-php-handler.md": "3b678eb1d69fe32dfcfdc05d36b33e49e01b79d7216bd784f6a61a6f1c3c3a13", "polyglot/namespace-auth-workers.md": "2b4078ceb74b849f12cb1975b410ff8e7266cd4345f6cf1d4dd906db12460ffb", - "polyglot/php.md": "04f7eeebf842bbcd2f278f96ee21fbbf4f97d424a27e717d65e1c73273bce095", + "polyglot/php.md": "309e83622754b9d9abc65807280f2dab175a009054a001456ef1316776f11101", "polyglot/polling-patterns.md": "30875099a23731c6c471b481a771378acc6ff57eed2fda4405a509057534c989", "polyglot/portable-worker-affinity.md": "40973c6a31a76845b4f95e9a505e68ad76abd5174bbdccf37993cdebc8904959", "polyglot/prerelease-history-migration.md": "a57f05f492228a8a67791f9152648a1e5f80856325b78777cf63b6ef49b7413c", @@ -105,6 +105,6 @@ "sdk-neutrality.md": "7b0714c123ade4904591870fc20e9a797da1e5485b2a6c87ca3eaa00c5de6ed6", "sponsors.md": "e85e14375743ca8fa50e3a48f894b160e28272573aa88480064f74010ebee98a", "support.md": "706807b3902599dda6080f632ec1f893017ea18bbe9585f533dcdbd6d85f4621", - "testing.md": "250bc7dfd46f99eaeb392b329947813b064bda72026645198e3aefc80043a813", + "testing.md": "176abf226936c7711c2df523fb8a94e92fcf62e6f804d99f2e32b9135f626547", "waterline-operator-api.md": "2aca03b2c14100060b40be0bb033a82525ba924908834e9060ec746ead26f36d" } diff --git a/i18n/uk/docusaurus-plugin-content-docs/current/compatibility.md b/i18n/uk/docusaurus-plugin-content-docs/current/compatibility.md index 036779d68e2..2d5b885817a 100644 --- a/i18n/uk/docusaurus-plugin-content-docs/current/compatibility.md +++ b/i18n/uk/docusaurus-plugin-content-docs/current/compatibility.md @@ -98,12 +98,12 @@ OpenAPI, AsyncAPI чи JSON Schema. Schema | Лінійка пакета | PHP | Laravel | | --- | --- | --- | -| Поточний вбудований Workflow 2.24 | PHP 8.2+ у 8.x; PHP 8.3+ для Laravel 13 | `^12.69.0` або `^13.30.0` | +| Поточний вбудований Workflow 2.26 | PHP 8.2+ у 8.x; PHP 8.3+ для Laravel 13 | `^12.69.0` або `^13.30.0` | | Вбудований Workflow 2.20.5 | PHP `^8.1` з урахуванням мінімуму фреймворку | `^10.50.4`, `^11.56.1`, `^12.69.0` або `^13.30.0` | | Опублікований PHP SDK 3.14 | Базовий SDK PHP `^8.1`; міст Laravel потребує PHP `^8.2`, а для Laravel 13 — PHP 8.3+ | `^12.69.0` або `^13.30.0` | | PHP SDK 3.9.5 | Базовий SDK PHP `^8.1`; міст Laravel також дотримується мінімуму фреймворку | `^10.50.4`, `^11.56.1`, `^12.69.0` або `^13.30.0` | -Першоджерела пакета — [опублікований контракт вбудованого оновлення](https://github.com/durable-workflow/workflow/blob/2.24.0/resources/laravel-embedded-upgrade-contract.json) +Першоджерела пакета — [опублікований контракт вбудованого оновлення](https://github.com/durable-workflow/workflow/blob/2.26.0/resources/laravel-embedded-upgrade-contract.json) і `composer.json` кожного випуску. Поточний вбудований випуск перевірено з Laravel 12/PHP 8.2–8.4 та Laravel 13/PHP 8.3–8.4. Підтримку PHP 8.1 і Laravel 10/11 вилучено. [Історичний посібник стабільної v1](/docs/1.x/installation/) та @@ -142,6 +142,16 @@ Workflow 2.23 і 2.24 зберігають мінімальні вимоги 2.2 Див. примітки до випусків [2.23.0](https://github.com/durable-workflow/workflow/releases/tag/2.23.0), [2.23.1](https://github.com/durable-workflow/workflow/releases/tag/2.23.1), [2.23.2](https://github.com/durable-workflow/workflow/releases/tag/2.23.2) та [2.24.0](https://github.com/durable-workflow/workflow/releases/tag/2.24.0). +Workflow 2.25 і 2.26 зберігають мінімальні вимоги 2.21 і вбудований протокол workers `1.22`. 2.25 не додає міграцій бази даних. 2.26 додає одну, тож під час оновлення виконайте `php artisan migrate`. Вона створює таблицю `workflow_child_supervisions`. Зміни, які варто перевірити перед оновленням: + +- Починаючи з 2.26, батьківський workflow, який продовжується як новий запуск, поки запущені ним дочірні workflow ще відкриті, передає їх продовженому запуску. Останній запуск ланцюжка застосовує до них політику закриття батьківського workflow, а дочірній workflow, що завершився помилкою, і далі повторюється згідно із записаною політикою повторних спроб. Див. [Continue-as-new і відкриті дочірні workflow](./features/child-workflows.md#continue-as-new-and-open-children). +- Починаючи з 2.26, міграції з попередніх випусків, які заповнюють наявні рядки (`2026_07_13`, `2026_09_24`, `2026_09_29` і `2026_10_11`), більше не блокують таблицю на весь час заповнення. Вони спочатку додають стовпець, заповнюють рядки невеликими пакетами, а потім будують індекси без блокування записів. Якщо одну з них перервано, знову виконайте `php artisan migrate`. Інсталяцій, які вже виконали ці міграції, це не стосується. +- Починаючи з 2.26, redrive повторно використовує дочірній workflow, що завершився до помилки. Випуски до 2.26 відтворюють такого наступника з іншим часом workflow після повторно використаного дочірнього workflow, тож щойно такий наступник існує, тримайте workers на 2.26 або новішій версії. Див. [Redrive невдалого запуску](./failures-and-recovery.md#redrive). +- Починаючи з 2.26, `historyBudgetAtStep()` і `shouldContinueAsNewAtStep()` зчитують бюджет історії однаково під час кожного відтворення. Використовуйте їх у циклах. Див. [Бюджет історії](./features/continue-as-new.md#history-budget). +- Починаючи з 2.25, перевищення фіксованого обмеження memo або атрибута пошуку викидає `StructuralLimitExceededException` замість `InvalidArgumentException`, а типове значення `memo_size_bytes` становить 65 536. Див. [Структурні обмеження](./constraints/structural-limits.md). + +Див. примітки до випусків [2.25.0](https://github.com/durable-workflow/workflow/releases/tag/2.25.0) та [2.26.0](https://github.com/durable-workflow/workflow/releases/tag/2.26.0). + ## Рівні стабільності {#stability-levels} Кожна публічна поверхня Durable Workflow має рівно один із цих рівнів diff --git a/i18n/uk/docusaurus-plugin-content-docs/current/defining-workflows/workflow-api.md b/i18n/uk/docusaurus-plugin-content-docs/current/defining-workflows/workflow-api.md index 11b39834923..b0eff09233e 100644 --- a/i18n/uk/docusaurus-plugin-content-docs/current/defining-workflows/workflow-api.md +++ b/i18n/uk/docusaurus-plugin-content-docs/current/defining-workflows/workflow-api.md @@ -46,6 +46,8 @@ abstract class Workflow public function historyLength(): int; public function historySize(): int; public function shouldContinueAsNew(): bool; + public function historyBudgetAtStep(): array; + public function shouldContinueAsNewAtStep(): bool; } ``` @@ -58,6 +60,8 @@ abstract class Workflow | `historyLength()` | Workflow потрібен кількісний показник бюджету історії. | Поточна кількість подій історії. | | `historySize()` | Workflow потрібен показник бюджету історії в байтах. | Приблизний розмір збереженої історії в байтах. | | `shouldContinueAsNew()` | Workflow має перейти до нового запуску до того, як історія стане дорогою. | `true`, якщо налаштовані бюджети історії рекомендують перехід. | +| `historyBudgetAtStep()` | Workflow зчитує бюджет більше одного разу за запуск, наприклад у циклі (Workflow 2.26+). | Лічильники бюджету станом на поточний крок, однакові під час кожного відтворення. | +| `shouldContinueAsNewAtStep()` | Цикл вирішує, чи переходити до нового запуску (Workflow 2.26+). | `true`, якщо історія до поточного кроку перевищує налаштований бюджет. | ## Стійкі команди {#durable-commands} diff --git a/i18n/uk/docusaurus-plugin-content-docs/current/failures-and-recovery.md b/i18n/uk/docusaurus-plugin-content-docs/current/failures-and-recovery.md index c74fa533f47..2f547394468 100644 --- a/i18n/uk/docusaurus-plugin-content-docs/current/failures-and-recovery.md +++ b/i18n/uk/docusaurus-plugin-content-docs/current/failures-and-recovery.md @@ -119,6 +119,7 @@ Redrive продовжує невдалий запуск у новому зап - Memo чи атрибут пошуку, які код workflow задав через upsert перед невдалим кроком, повторно використовуються в порядку кроків, і наступник зберігає ті самі значення. - Очікування signal (`await('name')`), яке отримало й застосувало свій signal, повторно використовується зі значенням цього signal. Signal не доставляється повторно. - Update, який було прийнято, застосовано й завершено до невдалого кроку, записується знову на тій самій позиції. Replay запускає handler update з записаними аргументами, тож стан workflow збігається. Update не доставляється вдруге. Відхилений update і update, який помилка закрила до виконання, пропускаються. +- У Workflow 2.26 і новіших виклик дочірнього workflow, що завершився перед невдалим кроком, повертає свій записаний результат. Дочірній workflow не запускається знову. Наступник записує події виклику `ChildWorkflowScheduled`, `ChildRunStarted` і `ChildRunCompleted` та зберігає початковий екземпляр дочірнього workflow, дочірній запуск, id зв’язку та id виклику, але не отримує власного дочірнього зв’язку. - `outbox()->sendReference()` та `inbox()->receive()` у повторно використаному коді workflow повертають повідомлення, яке невдалий запуск надіслав або спожив. Вони не надсилають і не споживають його вдруге. Receive у replay, початковий виклик якого нічого не знайшов, читає stream знову. - У Workflow 2.20.2 і новіших вхідні повідомлення stream, які ще чекають на обробку в невдалому запуску, переходять до наступника. Workflow 2.20.1 і раніші версії залишали їх у невдалому запуску, тож наступник ніколи їх не отримував ([workflow#1013](https://github.com/durable-workflow/workflow/issues/1013)). - Якщо запуск завершила помилка activity, невдалий виклик activity планується як нове виконання activity з політикою повторних спроб із коду workflow. Його спроби починаються заново. @@ -128,7 +129,7 @@ Redrive продовжує невдалий запуск у новому зап - Наступник зберігає дедлайн виконання невдалого запуску. Його тайм-аут запуску починається заново в момент redrive. - Кожен повторно використаний крок містить `reused_from_run_id` і `reused_recorded_at`. Для повторно використаної події update чи signal ці два поля завжди йдуть парою. - Наступника, який повторно використав кроки, можна знову запустити через redrive. Повторно використаний payload signal чи update зберігає в `workflow_run_id` запуск, який першим його записав, `reused_from_run_id` вказує на запуск, з якого зроблено redrive, а кожен повторно використаний крок зберігає час свого першого виконання, тож ланцюжок redrive використовує кожен крок лише раз. -- В embedded mode `Workflow::now()` у наступнику починається з часу старту невдалого запуску. Відтворення використовує `reused_recorded_at`, тому `Workflow::now()` після повторно використаного кроку збігається з часом у невдалому запуску. Крок, повторно використаний другим redrive, зберігає час свого першого виконання. +- В embedded mode `Workflow::now()` у наступнику починається з часу старту невдалого запуску. Відтворення використовує `reused_recorded_at`, тому `Workflow::now()` після повторно використаного кроку збігається з часом у невдалому запуску. Після повторно використаного виклику дочірнього workflow це час, коли дочірній workflow уперше завершився. Крок, повторно використаний другим redrive, зберігає час свого першого виконання. ### Запит на redrive {#request-a-redrive} @@ -184,11 +185,12 @@ Redrive приймає невдалий запуск, коли виконуют - Запуск є поточним запуском екземпляра. - Запуск завершився помилкою, бо помилка activity дійшла до коду workflow і не була перехоплена, або бо код workflow викинув виняток чи його зупинив структурний ліміт. Запуск, що впав на тайм-ауті workflow, відхиляється. -- Кожен крок перед невдалим кроком є завершеною activity, побічним ефектом, маркером версії, `timer()`, що спрацював, upsert для memo чи атрибута пошуку, очікуванням signal, яке отримало й застосувало свій signal, або update, який було прийнято, застосовано й завершено з тими самими аргументами. Відхилений update і update, який помилка закрила до виконання, допускаються й пропускаються. Payload activity, побічних ефектів, signal і update мають зберігатися inline. Payload у зовнішньому сховищі payload відхиляється. +- Кожен крок перед невдалим кроком є завершеною activity, побічним ефектом, маркером версії, `timer()`, що спрацював, upsert для memo чи атрибута пошуку, очікуванням signal, яке отримало й застосувало свій signal, update, який було прийнято, застосовано й завершено з тими самими аргументами, або, у Workflow 2.26 і новіших, завершеним викликом дочірнього workflow. Відхилений update і update, який помилка закрила до виконання, допускаються й пропускаються. Payload activity, побічних ефектів, signal, update і результатів дочірніх workflow мають зберігатися inline. Payload у зовнішньому сховищі payload відхиляється. - Визначення workflow збігається з відбитком, записаним під час старту запуску, або ви передали `allow_definition_change` і виправлений код відтворює завершені кроки. Помилка в коді workflow на тому самому визначенні відхиляється. - Дедлайн виконання ще не минув. -- Запуск не має батьківського workflow, дочірніх workflow чи локальних activity, а його вхідні дані збережено inline. -- Якщо запуск стартував сервісний worker, кроки перед помилкою можуть бути лише activity, побічними ефектами, маркерами версій і таймерами, що спрацювали. Upsert для memo й атрибутів пошуку, очікування signal і застосовані update відхиляються для сервісних запусків. +- Запуск не має батьківського workflow і локальних activity, а його вхідні дані збережено inline. До Workflow 2.26 він також не має дочірніх workflow. Для запуску, який сам є дочірнім, redrive ніколи не виконується, бо його батьківський workflow уже записав результат дочірнього. +- Кожен виклик дочірнього workflow перед невдалим кроком завершився сам по собі, поза паралельною групою чи областю скасування, без повторної спроби чи continue-as-new. +- Якщо запуск стартував сервісний worker, кроки перед помилкою можуть бути лише activity, побічними ефектами, маркерами версій і таймерами, що спрацювали. Upsert для memo й атрибутів пошуку, очікування signal, застосовані update і завершені виклики дочірніх workflow відхиляються для сервісних запусків. Відмова називає перше правило, яке не виконано: @@ -198,7 +200,12 @@ Redrive приймає невдалий запуск, коли виконуют | `source_run_not_current` | Існує новіший запуск екземпляра. | | `unrecorded_failure_boundary` | Для помилки запуску немає записаного кроку. Так буває, наприклад, з помилкою в коді workflow, записаною релізом до 2.19.0. | | `workflow_code_failure_requires_corrected_definition` | Код workflow викинув виняток, а визначення не змінилося, тож той самий код викине його знову. | -| `unsupported_history` | Історія до помилки містить крок, який redrive не може повторно використати, наприклад дочірній workflow чи скасований таймер. | +| `unsupported_history` | Історія до помилки містить крок, який redrive не може повторно використати, наприклад скасований таймер. До Workflow 2.26 — будь-який дочірній workflow. | +| `unsupported_open_child` | Виклик дочірнього workflow перед помилкою так і не закрився. Workflow 2.26 і новіші. | +| `unsupported_child_outcome` | Дочірній workflow перед помилкою завершився помилкою, був скасований або примусово завершений. Workflow 2.26 і новіші. | +| `unsupported_child_workflow` | Виклик дочірнього workflow перебуває в паралельній групі чи області скасування, повторювався або продовжувався як новий запуск, або його події не вказують на один дочірній виклик. Workflow 2.26 і новіші. | +| `external_child_result_not_supported` | Результат завершеного дочірнього workflow збережено в зовнішньому сховищі payload. Workflow 2.26 і новіші. | +| `unavailable_child_result` | Результат завершеного дочірнього workflow не декодується. Workflow 2.26 і новіші. | | `unsupported_local_activity` | Історія містить локальну activity. | | `unsupported_timer` | Історія містить тайм-аут умови чи signal, таймер очищення після скасування або таймер в межах області скасування чи паралельної групи. | | `incomplete_timer_step` | Кроку таймера бракує події планування чи події спрацювання. | @@ -225,7 +232,7 @@ Redrive приймає невдалий запуск, коли виконуют | `definition_incompatible_with_prefix` | Виправлений код не може відтворити завершені кроки. `definition_mismatch` називає перший відмінний крок. | | `definition_check_over_budget` | Завершена історія більша за бюджет історії, який дозволяє перевірка відтворення. | | `definition_change_requires_replay_check` | Запуск стартував сервісний worker, тому redrive не може перевірити змінене визначення. | -| `service_redrive_history_not_qualified` | Запуск стартував сервісний worker, і кроки перед помилкою містять upsert для memo, upsert для атрибута пошуку, очікування signal або застосований update. Redrive відхиляє такі кроки для сервісних запусків, доки не зможе перевірити для кожного runtime SDK, чи вміє той відтворювати їх у replay. | +| `service_redrive_history_not_qualified` | Запуск стартував сервісний worker, і кроки перед помилкою містять upsert для memo, upsert для атрибута пошуку, очікування signal, застосований update або завершений виклик дочірнього workflow. Redrive відхиляє такі кроки для сервісних запусків, доки не зможе перевірити для кожного runtime SDK, чи вміє той відтворювати їх у replay. | | `request_id_already_used` | `request_id` уже використано для іншого redrive екземпляра. | | `already_redriven` | Повідомляють деталі запуску та `describe()` для запуску, який уже запущено через redrive. Запит redrive для нього повертає наявного наступника. | | `invalid_request_id` | `request_id` довший за 191 символ. | @@ -247,6 +254,8 @@ Redrive приймає невдалий запуск, коли виконуют ### Попередні релізи та нативний Server {#redrive-earlier-releases} +Релізи Workflow до 2.26.0 відхиляють будь-який дочірній workflow в історії з `unsupported_history`. Вони ігнорують `reused_recorded_at` на подіях дочірніх workflow, тож наступник із 2.26.0, який повторно використав виклик дочірнього workflow, може відтворюватися в них з іншим часом workflow та іншими дедлайнами після цього виклику. Вони також відхиляють повторний redrive такого наступника. Щойно такий наступник існує, перед відкатом залиште workers на 2.26.0 чи новіших або переконайтеся, що жодна така історія не може відтворюватися. + Workflow 2.20.0 не відхиляє нічого з того, що приймає 2.20.1. У 2.20.0 `outbox()->sendReference()` у повторно використаному коді workflow надсилає повторно, а `inbox()->receive()` у replay може повернути інші повідомлення чи жодного або спожити новіше повідомлення ([workflow#1010](https://github.com/durable-workflow/workflow/issues/1010)). Workflow 2.19.0 відхиляє застосований update (`unsupported_history`). Він також відхиляє redrive наступника, який повторно використав update (`unsupported_history`) чи очікування signal (`mismatched_signal_receipt`). Деталі запуску та `describe()` показують зв’язки redrive як діагностичний запасний варіант. diff --git a/i18n/uk/docusaurus-plugin-content-docs/current/features/child-workflows.md b/i18n/uk/docusaurus-plugin-content-docs/current/features/child-workflows.md index 779b4a30276..e38555ee207 100644 --- a/i18n/uk/docusaurus-plugin-content-docs/current/features/child-workflows.md +++ b/i18n/uk/docusaurus-plugin-content-docs/current/features/child-workflows.md @@ -200,7 +200,7 @@ $results = all([ - Коли батьківський запуск закривається з будь-якої причини, рушій знаходить відкриті дочірні зв’язки з політикою, відмінною від abandon, і надсилає відповідну команду (request cancellation, cancel або terminate) кожному відкритому дочірньому workflow. - Якщо на момент застосування політики дочірній workflow уже закрито, команда пропускається без додаткової дії. - Політика застосовується за можливості: відхилення дочірньої команди, наприклад через уже термінальний стан дочірнього workflow, не впливає на закриття батьківського. Успішне застосування записує подію історії `ParentClosePolicyApplied` у батьківський запуск. У разі помилки натомість записується `ParentClosePolicyFailed`, щоб оператори могли відрізнити успішне застосування від непомітного збою. -- Continue-as-new **не** запускає політику закриття батьківського workflow, оскільки його екземпляр залишається активним у новому запуску. +- Continue-as-new **не** запускає політику закриття батьківського workflow, оскільки його екземпляр залишається активним у новому запуску. Починаючи з Workflow 2.26, натомість її застосовує останній запуск ланцюжка. Див. [Continue-as-new і відкриті дочірні workflow](#continue-as-new-and-open-children). ### Матриця результатів батьківського workflow {#parent-disposition-matrix} @@ -213,9 +213,21 @@ $results = all([ | Сплив тайм-ауту | Так | Після запису `WorkflowTimedOut` через тайм-аут запуску або виконання. | | Скасування | Так | Після того, як прийнята команда `CancelRequested` закриває батьківський запуск. | | Примусове завершення | Так | Після того, як прийнята команда `TerminateRequested` закриває батьківський запуск. | -| Продовження як новий запуск | Ні | Екземпляр workflow залишається активним у новому запуску, тому наявні дочірні зв’язки спрямовуються на продовжений запуск зі збереженням початкової політики. | +| Продовження як новий запуск | Ні | Екземпляр workflow залишається активним у новому запуску. Починаючи з Workflow 2.26, продовжений запуск перебирає нагляд за відкритими дочірніми workflow, а останній запуск ланцюжка застосовує їхню політику. | | Скидання | Наразі не застосовується | Середовище виконання v2 не надає окремої команди reset або термінального результату reset. Майбутня операція reset чи repair, яка закриває або замінює батьківський запуск, має визначити, чи передається володіння дочірніми workflow. Якщо старий запуск стає термінальним, він має застосувати політику закриття перед припиненням володіння відкритими дочірніми workflow. | +### Continue-as-new і відкриті дочірні workflow {#continue-as-new-and-open-children} + +У Workflow 2.26 і новіших батьківський workflow, який продовжується як новий запуск, поки запущені ним дочірні workflow ще відкриті, передає їх продовженому запуску в тій самій транзакції. Вбудовані запуски й запуски в сервісному режимі поводяться однаково: + +- Кожен відкритий дочірній workflow отримує рядок у таблиці `workflow_child_supervisions`, яку створює міграція 2.26. Дочірній workflow, що вже закрився, не передається. +- Дочірній зв’язок, дочірній виклик, послідовність, дедлайни й політика закриття батьківського workflow лишаються такими, як їх записав початковий запуск. Коли продовжений запуск знову продовжується як новий, він знову передає дочірні workflow. +- Коли останній запуск ланцюжка успішно завершується, завершується помилкою, вичерпує тайм-аут, скасовується або примусово завершується, він застосовує політику кожного дочірнього workflow і записує `ParentClosePolicyApplied` або `ParentClosePolicyFailed` у власну історію. `abandon` лишається `abandon`. Закритий попередній запуск не отримує нової історії. +- Продовжений запуск не має дескрипторів цих дочірніх workflow, і їхні результати йому не доставляються. Передайте все, що потрібно наступному запуску, в аргументах `continueAsNew()`. +- Переданий дочірній workflow, що завершився помилкою, повторюється згідно з політикою повторних спроб, яку записав початковий запуск, з тією самою ідентичністю дочірнього виклику та лічильником спроб, поки за ним ще наглядає якийсь запуск ланцюжка. `WorkflowStarted` повторного запуску вказує початковий запуск як батьківський, а останній запуск ланцюжка застосовує політику закриття батьківського workflow до повторного запуску. Помилка стає остаточною, коли спроби вичерпано, помилка не допускає повторення або ланцюжок закрито. + +До 2.26 такі дочірні workflow продовжували виконуватися після закриття ланцюжка, їхня політика ніколи не застосовувалася, а дочірній workflow, що завершився помилкою після continue-as-new батьківського, не повторювався. Див. [примітки до випуску 2.26.0](https://github.com/durable-workflow/workflow/releases/tag/2.26.0). + ### Коли використовувати кожну політику {#when-to-use-each-policy} **Abandon** (типова політика) підходить, коли дочірні workflow представляють незалежну роботу, яка має завершитися незалежно від долі батьківського workflow, наприклад workflow сповіщень або обов’язкове завдання очищення. diff --git a/i18n/uk/docusaurus-plugin-content-docs/current/features/continue-as-new.md b/i18n/uk/docusaurus-plugin-content-docs/current/features/continue-as-new.md index 8e6c1d26c5d..69aa08170e6 100644 --- a/i18n/uk/docusaurus-plugin-content-docs/current/features/continue-as-new.md +++ b/i18n/uk/docusaurus-plugin-content-docs/current/features/continue-as-new.md @@ -82,6 +82,10 @@ Core 2.7.0 і сумісні Server зберігають прийняті сиг Код workflow може перевіряти поточну довжину історії та прапорець рекомендації continue-as-new через явний контекст runtime. Це дає тривалим циклам змогу свідомо передавати виконання до досягнення граничного бюджету історії. +У Workflow 2.26 і новіших використовуйте `shouldContinueAsNewAtStep()` і `historyBudgetAtStep()`. Вони враховують лише історію, записану до поточного кроку workflow, тож той самий рядок повертає ту саму відповідь під час кожного відтворення. Цикл, який перевіряє бюджет на кожній ітерації, продовжується як новий запуск один раз — на першій ітерації, що перетинає поріг. + +Старіші методи читають усю поточну історію. У циклі попередня ітерація під час відтворення може побачити пізнішу загальну кількість і піти іншою гілкою, ніж уперше. Ці методи не змінено, тож запуски, які вже ухвалили рішення з їхньою допомогою, і далі відтворюються. + ```php use function Workflow\V2\activity; use function Workflow\V2\continueAsNew; @@ -109,6 +113,8 @@ class PollingWorkflow extends Workflow | `$this->historyLength()` | `int` | Кількість подій історії поточного запуску | | `$this->historySize()` | `int` | Загальний розмір подій історії в байтах | | `$this->shouldContinueAsNew()` | `bool` | `true`, коли запуск перевищує налаштований бюджет кількості подій або розміру в байтах | +| `$this->historyBudgetAtStep()` | `array` | Бюджет станом на поточний крок: `history_event_count`, `history_size_bytes`, `history_fan_out`, `continue_as_new_recommended`, `pressure`, `pressure_dimensions` і `observation` (`step_prefix.v1`). Workflow 2.26 і новіші. | +| `$this->shouldContinueAsNewAtStep()` | `bool` | `continue_as_new_recommended` з `historyBudgetAtStep()`. Використовуйте в циклах. Workflow 2.26 і новіші. | ### Налаштування {#configuration} @@ -124,7 +130,7 @@ class PollingWorkflow extends Workflow ], ``` -`shouldContinueAsNew()` повертає `true` після перетину будь-якого порога. Стислі представлення запусків також відстежують `history_event_count`, `history_size_bytes` та `continue_as_new_recommended`, щоб Waterline міг позначати тривалі запуски в загальних представленнях. +`shouldContinueAsNew()` і `shouldContinueAsNewAtStep()` повертають `true` після перетину будь-якого порога. Стислі представлення запусків також відстежують `history_event_count`, `history_size_bytes` та `continue_as_new_recommended`, щоб Waterline міг позначати тривалі запуски в загальних представленнях. ## Перенесення метаданих {#metadata-carry-forward} @@ -164,6 +170,8 @@ class PollingWorkflow extends Workflow } ``` +Батьківський workflow, який продовжується як новий запуск, поки запущені ним дочірні workflow ще відкриті, передає їх продовженому запуску. Див. [Continue-as-new і відкриті дочірні workflow](./child-workflows.md#continue-as-new-and-open-children). + Для тривалих циклів введення користувачем або роботи асистента обирайте повноцінний фасад `$this->inbox()` / `$this->outbox()` [Потоків повідомлень](./message-streams.md). Повідомлення потоку, які ще чекають diff --git a/i18n/uk/docusaurus-plugin-content-docs/current/features/search-attributes.md b/i18n/uk/docusaurus-plugin-content-docs/current/features/search-attributes.md index 235d666de5a..c23cd25961b 100644 --- a/i18n/uk/docusaurus-plugin-content-docs/current/features/search-attributes.md +++ b/i18n/uk/docusaurus-plugin-content-docs/current/features/search-attributes.md @@ -105,7 +105,7 @@ $controlPlane->start('orders.process-order', 'order-42', [ Реєстрація обмежує лише ті ключі, які ви реєструєте. Починаючи з нативного Server 3.5.0, незареєстрований ключ і далі приймається, а його тип визначається автоматично, як у namespace без зареєстрованих атрибутів. Реєстрація одного атрибута не ламає запущені workflows, які виконують upsert інших ключів. PHP Server 2.x і нативний Server до 3.5.0 відхиляють кожен незареєстрований ключ, щойно зареєстровано будь-який атрибут, тож там зареєструйте всі ключі, які використовують ваші workflows, перш ніж реєструвати перший. -Видалення реєстрації припиняє перевірку цього ключа. Збережені значення й запущені workflows не змінюються, а наступні upsert цього ключа знову визначають тип автоматично. +Видалення реєстрації припиняє перевірку цього ключа. Збережені значення й запущені workflows не змінюються, а наступні upsert цього ключа знову визначають тип автоматично. У нативному Server запит списку, що фільтрує за незареєстрованим ключем, зокрема за ключем, реєстрацію якого ви видалили, відхиляється, бо цей ключ не визначено в namespace. Щоб змінити тип атрибута, зареєструйте нову назву атрибута з новим типом, оновіть workflows, щоб вони записували її, і фільтруйте за новою назвою, коли наявні запуски її наздоженуть. Якщо видалити й повторно зареєструвати ту саму назву з іншим типом, попередні значення залишаться в старому типі. diff --git a/i18n/uk/docusaurus-plugin-content-docs/current/polyglot/php.md b/i18n/uk/docusaurus-plugin-content-docs/current/polyglot/php.md index e2ca7758269..cd4ff0016f8 100644 --- a/i18n/uk/docusaurus-plugin-content-docs/current/polyglot/php.md +++ b/i18n/uk/docusaurus-plugin-content-docs/current/polyglot/php.md @@ -302,7 +302,7 @@ PHP `^8.1`, мінімальні вимоги мосту Laravel, протоко - **Sticky-суфікси історії (3.14).** Workers оголошують `sticky_history_suffix`. На Server 3.5.0 або новішому worker, який уже має історію запуску, отримує лише події після закешованої послідовності. Суфікс, що не продовжує закешовану історію точно, відкидається, і завантажується повна історія. Старіші Server і далі надсилають повну історію. - **Походження розкладу (3.13).** `WorkflowContext::scheduleOrigin()` повертає id розкладу, час спрацювання та номер запуску розкладу, який стартував цей запуск, або `null` для звичайного старту. Під час replay значення те саме. Починаючи з Server 3.5.0, запуск, продовжений через continue-as-new, зберігає походження розкладу. -- **Продовження активностей (3.12).** Передайте `enableActivityContinuation: true` у конструктор `Worker`, щоб надсилати наступні команди workflow разом з успішним результатом активності, коли Server оголошує `activity_workflow_continuation` (нативний Server 3.4.0 або новіший). Типове значення — `false`. Якщо вмикаєте, використовуйте 3.12.1 або новішу версію, а перед пониженням Server чи додаванням старіших вузлів Server спорожніть або вимкніть такі workers. +- **Продовження активностей (3.12).** Передайте `enableActivityContinuation: true` у конструктор `Worker`, щоб надсилати наступні команди workflow разом з успішним результатом активності, коли Server оголошує `activity_workflow_continuation` (нативний Server 3.4.0 або новіший). Типове значення — `false`. Наразі його ввімкнення знижує пропускну здатність: у нашому бенчмарку під навантаженням workflows виконувалися на 24–49% повільніше з увімкненим параметром і використовували вдвічі більше транзакцій бази даних ([вимірювання](https://github.com/durable-workflow/server/issues/1078)). Якщо вмикаєте, використовуйте 3.12.1 або новішу версію, а перед пониженням Server чи додаванням старіших вузлів Server спорожніть або вимкніть такі workers. Повний перелік див. у [журналі змін 3.14.0](https://github.com/durable-workflow/sdk-php/blob/3.14.0/CHANGELOG.md). diff --git a/i18n/uk/docusaurus-plugin-content-docs/current/testing.md b/i18n/uk/docusaurus-plugin-content-docs/current/testing.md index 37f69aa7e5c..e0205709319 100644 --- a/i18n/uk/docusaurus-plugin-content-docs/current/testing.md +++ b/i18n/uk/docusaurus-plugin-content-docs/current/testing.md @@ -384,7 +384,9 @@ public function testReturnExistingActiveStart(): void `continue_as_new_recommended`) надаються проєкцією огляду run й доступні через `RunDetailView`. У коді workflow базовий клас `Workflow` надає їх як `$this->historyLength()`, `$this->historySize()` і -`$this->shouldContinueAsNew()`: +`$this->shouldContinueAsNew()`. У циклі використовуйте +`$this->shouldContinueAsNewAtStep()` (Workflow 2.26 і новіші), який дає ту саму +відповідь під час кожного відтворення: ```php use Workflow\V2\Workflow; @@ -396,7 +398,7 @@ final class LongRunningWorkflow extends Workflow while (true) { // ... process work ... - if ($this->shouldContinueAsNew()) { + if ($this->shouldContinueAsNewAtStep()) { Workflow::continueAsNew($this->carryForwardState()); } } diff --git a/i18n/uk/source-hashes.json b/i18n/uk/source-hashes.json index aaa9e3d33f5..29802b30c7c 100644 --- a/i18n/uk/source-hashes.json +++ b/i18n/uk/source-hashes.json @@ -4,7 +4,7 @@ "ai-agent-workflow-engine.md": "28016466b179adbabdff6467ce351100c9bee48529a8bec9df7ec22c8d786d4d", "ai-assisted-development.md": "b246bb60585fb7a69bc534978f470f3f16e899e1f8f203ba0847d2d11b8a1ec3", "capabilities.md": "d9a2bbc0d04adf8cb3f4c7f42d779a43aafab60791210305e7e476c0499528fc", - "compatibility.md": "567310faf420fbd5229c5eef69721e8b7d09f033333cbaec21b72acaf81b6690", + "compatibility.md": "ad5c8519be03ae1e7b6e5e03b05a886862fd67c603b241ecb5baf2be5cd59610", "configuration/customization-matrix.md": "3d115863eaee7852b541bcd01615f424cc19c5847c7cd7d75e5ae63bc3f5cc78", "configuration/database-connection.md": "cc83ae77133236309506fa44d39bfd0c939c32a6154c0bd6099bc64c83bdaec9", "configuration/ensuring-same-server.md": "6c665f37cc198c7b1a775a60a94aab5ff4e55383385e76f1834c7840559b512a", @@ -24,18 +24,18 @@ "defining-workflows/activities.md": "05b46f73477a0bbd5f21d17ac37def8a8eac53f1e629155805c98cc46e75b418", "defining-workflows/passing-data.md": "c5d36126b0b15f1780119f6418e8bbe5a63e03353be5a0bb69385206ef0ad635", "defining-workflows/starting-workflows.md": "722b80454b577b0715ff50db70c7cda2cd02c34c505dd1219a83307852d325a4", - "defining-workflows/workflow-api.md": "a6150e75302323b49f350159ce3568a51a19701bb81829915615f754592ee79c", + "defining-workflows/workflow-api.md": "3c13894c1fdbe77bb1379c62bbdb0ef213c81f1cba5b477d45402dcc7fe87237", "defining-workflows/workflow-id.md": "ca3b43253a748b27dca1af9f82fcf8c4c133e14f13e1b82eaa1ca2ed0996d4bf", "defining-workflows/workflow-status.md": "8e8cb27ff44c890d489d89bf166375acfdfaecabd990a2235e106fab1592d529", "defining-workflows/workflows.md": "f467bc73de32aa5d722c61ce085065460382ae7dd44cea4625847d9fcdc4c97c", "deployment.md": "6aa439b1ebfdc2affccaf6fe6fff7519776a4ffcad8d3cb5956b665e7c97257f", - "failures-and-recovery.md": "598b538e2bcb6a40a4f2d4c0c462705bab30ef96767144f6590c2cc93b68a98a", + "failures-and-recovery.md": "4209521a8783939d458658a7afea64124c34571080c97feb2868a273db88db3e", "features/activity-execution-model.md": "e8c37520ae46a7efb30438f4fc06bf893c1df430cb1f92c48963697adaf09082", "features/cancel-and-terminate.md": "cedd1e6c51dfa551e00edc1d39739ff1f67d558d2a0be92143f478cb6111536b", - "features/child-workflows.md": "57016591fb8816aed7b077e204f1c80f9c6a8dff7501bc00a141c41a4607306b", + "features/child-workflows.md": "278b634b8b48b94203309cdba27d6116897a2919cab19628add8cd85dadb08d3", "features/concurrency.md": "a7a3eb2274f7b14faf722494569b7663c07ab48afdf2e9225e58914b84cacbb4", "features/condition-waits.md": "451261eda990c9591a0db69839d872184b5c64da6b537a582133095b8d4b599e", - "features/continue-as-new.md": "50c79f317155e052a3f2f37d198a71bdfc496a454905293f40cf09d73138f25b", + "features/continue-as-new.md": "a5309192c685abeb5295071d423824ae2287e68d247a6661f18d3ab21f9bdc9c", "features/events.md": "c466df05908748489226a3d1410c9203cf6f2986a4bb7539db1c5f82715abc7b", "features/external-payload-storage.md": "acc312fa2f50a43c96e1d235439124d28a7048f0bf3abac34319467fcbf7e898", "features/heartbeats.md": "4fce9636d68c89f29f259d52e463cd67eccf0bc55ad4d53338ed03329892b365", @@ -45,7 +45,7 @@ "features/queries.md": "c66dd9542a062edd8158a46cebc9f1bf926aaf3599dca4a3122bd9860df6e2a2", "features/sagas.md": "046ba5661ccb5ac71a236356d243b021d9830123e3798afce491118434e83820", "features/schedules.md": "40d30b2767e7ed043e2b0c7180915c256accea3e7a3401c38d1bf75bfe1c2213", - "features/search-attributes.md": "567d89858cd82e86672b210154001a272b17a5f87e13dbfa7de1b8e093d615b8", + "features/search-attributes.md": "bb66d83f64e0098354d86ac237e6867b9819098044101ba9a60a6a00a3961dd1", "features/service-operations.md": "912131c0a8ef393040a933fb4a66e68abcb9d475a3ebd47c85287d4032f45a0e", "features/side-effects.md": "abdccab8d6fc1a12b3eff8a4ccc58730ac36f523559b4ad89c5c2a8d201a3b86", "features/signal+timer.md": "a05fc480544fa71f6c9b215ad3417f71b8475dd81f9de8ee18d7a3b69ac33a23", @@ -80,7 +80,7 @@ "polyglot/invocable-carrier.md": "d32d8b5c7c33204b342f977e0af734166d91e96073db1a49ccb4d414a6d67380", "polyglot/invocable-php-handler.md": "3b678eb1d69fe32dfcfdc05d36b33e49e01b79d7216bd784f6a61a6f1c3c3a13", "polyglot/namespace-auth-workers.md": "2b4078ceb74b849f12cb1975b410ff8e7266cd4345f6cf1d4dd906db12460ffb", - "polyglot/php.md": "04f7eeebf842bbcd2f278f96ee21fbbf4f97d424a27e717d65e1c73273bce095", + "polyglot/php.md": "309e83622754b9d9abc65807280f2dab175a009054a001456ef1316776f11101", "polyglot/polling-patterns.md": "30875099a23731c6c471b481a771378acc6ff57eed2fda4405a509057534c989", "polyglot/portable-worker-affinity.md": "40973c6a31a76845b4f95e9a505e68ad76abd5174bbdccf37993cdebc8904959", "polyglot/prerelease-history-migration.md": "a57f05f492228a8a67791f9152648a1e5f80856325b78777cf63b6ef49b7413c", @@ -105,6 +105,6 @@ "sdk-neutrality.md": "7b0714c123ade4904591870fc20e9a797da1e5485b2a6c87ca3eaa00c5de6ed6", "sponsors.md": "e85e14375743ca8fa50e3a48f894b160e28272573aa88480064f74010ebee98a", "support.md": "706807b3902599dda6080f632ec1f893017ea18bbe9585f533dcdbd6d85f4621", - "testing.md": "250bc7dfd46f99eaeb392b329947813b064bda72026645198e3aefc80043a813", + "testing.md": "176abf226936c7711c2df523fb8a94e92fcf62e6f804d99f2e32b9135f626547", "waterline-operator-api.md": "2aca03b2c14100060b40be0bb033a82525ba924908834e9060ec746ead26f36d" } diff --git a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/compatibility.md b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/compatibility.md index c4c02b33c95..f0d571f8317 100644 --- a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/compatibility.md +++ b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/compatibility.md @@ -65,12 +65,12 @@ import protocolCatalog from '@site/static/platform-protocol-specs.json'; | 包版本线 | PHP | Laravel | | --- | --- | --- | -| 当前嵌入式 Workflow 2.24 | PHP 8.x 中的 8.2+;Laravel 13 需要 PHP 8.3+ | `^12.69.0` 或 `^13.30.0` | +| 当前嵌入式 Workflow 2.26 | PHP 8.x 中的 8.2+;Laravel 13 需要 PHP 8.3+ | `^12.69.0` 或 `^13.30.0` | | 嵌入式 Workflow 2.20.5 | PHP `^8.1`,并满足框架自身最低要求 | `^10.50.4`、`^11.56.1`、`^12.69.0` 或 `^13.30.0` | | 已发布 PHP SDK 3.14 | 基础 SDK 为 PHP `^8.1`;Laravel 桥接需要 PHP `^8.2`,Laravel 13 需要 PHP 8.3+ | `^12.69.0` 或 `^13.30.0` | | PHP SDK 3.9.5 | 基础 SDK 为 PHP `^8.1`;Laravel 桥接还需满足框架的 PHP 要求 | `^10.50.4`、`^11.56.1`、`^12.69.0` 或 `^13.30.0` | -包的依据是[已发布的嵌入式升级契约](https://github.com/durable-workflow/workflow/blob/2.24.0/resources/laravel-embedded-upgrade-contract.json) +包的依据是[已发布的嵌入式升级契约](https://github.com/durable-workflow/workflow/blob/2.26.0/resources/laravel-embedded-upgrade-contract.json) 及各版本的 `composer.json`。当前嵌入式版本已验证 Laravel 12/PHP 8.2–8.4 与 Laravel 13/PHP 8.3–8.4, 不再支持 PHP 8.1 和 Laravel 10/11。[历史稳定 v1 安装指南](/docs/1.x/installation/)与 [PHP SDK 的独立要求](https://php.durable-workflow.com/)保持独立。 @@ -101,6 +101,16 @@ Workflow 2.23 和 2.24 保留 2.21 的支持下限和嵌入式 worker 协议 `1. 参见 [2.23.0](https://github.com/durable-workflow/workflow/releases/tag/2.23.0), [2.23.1](https://github.com/durable-workflow/workflow/releases/tag/2.23.1), [2.23.2](https://github.com/durable-workflow/workflow/releases/tag/2.23.2) 和 [2.24.0](https://github.com/durable-workflow/workflow/releases/tag/2.24.0) 的发布说明。 +Workflow 2.25 和 2.26 保留 2.21 的支持下限和嵌入式 worker 协议 `1.22`。2.25 不添加数据库迁移。2.26 添加一个,因此升级时请运行 `php artisan migrate`。它创建 `workflow_child_supervisions` 表。升级前需要检查的变化: + +- 自 2.26 起,父工作流在其启动的子工作流仍未关闭时 continue-as-new,会把这些子工作流交给继续运行。链中的最终运行会应用它们的父级关闭策略,失败的子工作流仍会按其记录的重试策略重试。参见[继续为新运行与未关闭的子工作流](./features/child-workflows.md#continue-as-new-and-open-children)。 +- 自 2.26 起,早期版本中回填现有行的迁移(`2026_07_13`、`2026_09_24`、`2026_09_29` 和 `2026_10_11`)不再在整个回填期间锁表。它们先添加列,再以小批量填充行,然后在不阻塞写入的情况下建立索引。如果其中某个迁移被中断,请再次运行 `php artisan migrate`。已运行过这些迁移的安装不受影响。 +- 自 2.26 起,redrive 会复用在失败之前已完成的子工作流。2.26 之前的版本重放这样的后继运行时,复用的子工作流之后的工作流时间会不同,因此一旦存在这样的后继运行,请继续使用 2.26 或更高版本的 worker。参见[对失败的运行执行 redrive](./failures-and-recovery.md#redrive)。 +- 自 2.26 起,`historyBudgetAtStep()` 和 `shouldContinueAsNewAtStep()` 在每次重放时以相同方式读取历史预算。请在循环中使用它们。参见[历史预算](./features/continue-as-new.md#history-budget)。 +- 自 2.25 起,超过固定的备忘录或搜索属性上限会抛出 `StructuralLimitExceededException`,而不是 `InvalidArgumentException`,且 `memo_size_bytes` 的默认值为 65,536。参见[结构限制](./constraints/structural-limits.md)。 + +参见 [2.25.0](https://github.com/durable-workflow/workflow/releases/tag/2.25.0) 和 [2.26.0](https://github.com/durable-workflow/workflow/releases/tag/2.26.0) 的发布说明。 + ## 稳定性级别 {#stability-levels} Durable Workflow 中每个公开接口恰好具有以下一个稳定性级别。级别必须明确;未分类的接口不是公开接口。 diff --git a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/defining-workflows/workflow-api.md b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/defining-workflows/workflow-api.md index 8fbda85bf37..31fff244b96 100644 --- a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/defining-workflows/workflow-api.md +++ b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/defining-workflows/workflow-api.md @@ -46,6 +46,8 @@ abstract class Workflow public function historyLength(): int; public function historySize(): int; public function shouldContinueAsNew(): bool; + public function historyBudgetAtStep(): array; + public function shouldContinueAsNewAtStep(): bool; } ``` @@ -58,6 +60,8 @@ abstract class Workflow | `historyLength()` | 工作流需要基于数量的历史预算指标。 | 当前历史事件数。 | | `historySize()` | 工作流需要基于字节的历史预算指标。 | 持久化历史大小的近似字节数。 | | `shouldContinueAsNew()` | 工作流应在历史成本变高前轮换运行。 | 配置的历史预算建议轮换时为 `true`。 | +| `historyBudgetAtStep()` | 工作流在一次运行中多次读取预算,例如在循环中(Workflow 2.26+)。 | 截至当前步骤的预算计数,每次重放都相同。 | +| `shouldContinueAsNewAtStep()` | 循环决定是否轮换运行(Workflow 2.26+)。 | 当前步骤之前的历史超过配置的预算时为 `true`。 | ## 持久命令 {#durable-commands} diff --git a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/failures-and-recovery.md b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/failures-and-recovery.md index fc27113c1ae..33b6c9fffcf 100644 --- a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/failures-and-recovery.md +++ b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/failures-and-recovery.md @@ -114,6 +114,7 @@ redrive 会在同一工作流实例的新运行中继续一个失败的运行。 - 工作流代码在失败步骤之前 upsert 的备忘录或搜索属性会按步骤顺序复用,后继运行保留相同的值。 - 已接收并应用其信号的信号等待(`await('name')`)会连同该信号的值一起复用。该信号不会再次投递。 - 在失败步骤之前已被接受、应用并完成的更新,会在相同位置重新记录。重放会用记录的参数运行更新处理程序,因此工作流状态保持一致。更新不会再次投递。被拒绝的更新,以及在执行前就被失败关闭的更新,会被省略。 +- 在 Workflow 2.26 及更高版本中,在失败步骤之前已完成的子工作流调用会返回其记录的结果。子工作流不会再次启动。后继运行会记录该调用的 `ChildWorkflowScheduled`、`ChildRunStarted` 和 `ChildRunCompleted` 事件,并保留原始的子工作流实例、子运行、链接 id 和调用 id,但自身不会获得子链接。 - 复用的工作流代码中的 `outbox()->sendReference()` 和 `inbox()->receive()` 会返回失败运行发送或消费过的消息,不会再次发送或消费。原始调用没有找到任何消息的 receive 在重放时会再次读取 stream。 - 在 Workflow 2.20.2 及之后的版本中,失败运行上仍待处理的入站 stream 消息会转移到后继运行。Workflow 2.20.1 及之前的版本会把它们留在失败运行上,因此后继运行永远收不到这些消息([workflow#1013](https://github.com/durable-workflow/workflow/issues/1013))。 - 如果运行因活动失败而结束,失败的活动调用会作为新的活动执行被调度,并使用工作流代码中的重试策略。它的尝试次数重新开始计算。 @@ -123,7 +124,7 @@ redrive 会在同一工作流实例的新运行中继续一个失败的运行。 - 后继运行保留失败运行的执行截止时间。它的运行超时从 redrive 时重新开始计算。 - 每个被复用的步骤都带有 `reused_from_run_id` 和 `reused_recorded_at`。在复用的更新或信号事件上,这两个字段总是成对出现。 - 复用过步骤的后继运行可以再次 redrive。复用的信号或更新负载会在 `workflow_run_id` 中保留最初记录它的运行,`reused_from_run_id` 指向它被 redrive 时的来源运行,且每个复用的步骤都保留其首次运行的时间,因此一连串 redrive 中每个步骤只复用一次。 -- 在嵌入式模式下,后继运行中的 `Workflow::now()` 从失败运行的开始时间起算。重放使用 `reused_recorded_at`,因此复用步骤之后的 `Workflow::now()` 与失败运行中的时间一致。被第二次 redrive 复用的步骤保留其首次运行的时间。 +- 在嵌入式模式下,后继运行中的 `Workflow::now()` 从失败运行的开始时间起算。重放使用 `reused_recorded_at`,因此复用步骤之后的 `Workflow::now()` 与失败运行中的时间一致。在复用的子工作流调用之后,该时间是子工作流首次完成的时间。被第二次 redrive 复用的步骤保留其首次运行的时间。 ### 请求 redrive {#request-a-redrive} @@ -179,11 +180,12 @@ $result = app(WorkflowControlPlane::class)->redrive($instanceId, $failedRunId, [ - 该运行是实例的当前运行。 - 运行失败的原因是活动失败到达工作流代码且未被捕获,或者是工作流代码抛出异常或结构限制使其停止。因工作流超时失败的运行会被拒绝。 -- 失败步骤之前的每个步骤都是已完成的活动、副作用、版本标记、已触发的 `timer()`、备忘录或搜索属性的 upsert、已接收并应用其信号的信号等待,或者以相同参数被接受、应用并完成的更新。被拒绝的更新,以及在执行前就被失败关闭的更新,是允许的,会被省略。活动、副作用、信号和更新的负载必须以内联方式存储。存放在外部负载存储中的负载会被拒绝。 +- 失败步骤之前的每个步骤都是已完成的活动、副作用、版本标记、已触发的 `timer()`、备忘录或搜索属性的 upsert、已接收并应用其信号的信号等待,以相同参数被接受、应用并完成的更新,或者(在 Workflow 2.26 及更高版本中)已完成的子工作流调用。被拒绝的更新,以及在执行前就被失败关闭的更新,是允许的,会被省略。活动、副作用、信号、更新和子工作流结果的负载必须以内联方式存储。存放在外部负载存储中的负载会被拒绝。 - 工作流定义与运行开始时记录的指纹一致,或者你传入了 `allow_definition_change` 且修正后的代码能够重放已完成的步骤。同一定义上的工作流代码失败会被拒绝。 - 执行截止时间尚未过去。 -- 运行没有父工作流、子工作流或本地活动,且其输入以内联方式存储。 -- 如果运行由服务模式 Worker 启动,失败之前的步骤只能是活动、副作用、版本标记和已触发的计时器。备忘录和搜索属性的 upsert、信号等待以及已应用的更新,在服务模式运行中会被拒绝。 +- 运行没有父工作流或本地活动,且其输入以内联方式存储。在 Workflow 2.26 之前,运行还不能有子工作流。本身是子工作流的运行永远不会被 redrive,因为其父工作流已经记录了该子工作流的结果。 +- 失败步骤之前的每个子工作流调用都独立完成,不在并行组或取消作用域中,且没有经过重试或 continue-as-new。 +- 如果运行由服务模式 Worker 启动,失败之前的步骤只能是活动、副作用、版本标记和已触发的计时器。备忘录和搜索属性的 upsert、信号等待、已应用的更新以及已完成的子工作流调用,在服务模式运行中会被拒绝。 拒绝结果会指出第一条未满足的规则: @@ -193,7 +195,12 @@ $result = app(WorkflowControlPlane::class)->redrive($instanceId, $failedRunId, [ | `source_run_not_current` | 该实例存在更新的运行。 | | `unrecorded_failure_boundary` | 运行的失败没有记录对应的步骤,例如 2.19.0 之前的版本记录的工作流代码失败。 | | `workflow_code_failure_requires_corrected_definition` | 工作流代码抛出了异常,且定义没有变化,因此同样的代码会再次抛出异常。 | -| `unsupported_history` | 失败之前的历史包含 redrive 无法复用的步骤,例如子工作流或已取消的计时器。 | +| `unsupported_history` | 失败之前的历史包含 redrive 无法复用的步骤,例如已取消的计时器。在 Workflow 2.26 之前,任何子工作流都属于此类。 | +| `unsupported_open_child` | 失败之前的某个子工作流调用从未关闭。Workflow 2.26 及更高版本。 | +| `unsupported_child_outcome` | 失败之前的某个子工作流失败、被取消或被终止。Workflow 2.26 及更高版本。 | +| `unsupported_child_workflow` | 某个子工作流调用位于并行组或取消作用域中,经过了重试或 continue-as-new,或者其事件没有指向单一的子工作流调用。Workflow 2.26 及更高版本。 | +| `external_child_result_not_supported` | 某个已完成子工作流的结果存储在外部负载存储中。Workflow 2.26 及更高版本。 | +| `unavailable_child_result` | 某个已完成子工作流的结果无法解码。Workflow 2.26 及更高版本。 | | `unsupported_local_activity` | 历史中包含本地活动。 | | `unsupported_timer` | 历史中包含条件或信号超时、取消清理计时器,或位于取消作用域或并行组中的计时器。 | | `incomplete_timer_step` | 某个计时器步骤没有同时具备调度事件和触发事件。 | @@ -220,7 +227,7 @@ $result = app(WorkflowControlPlane::class)->redrive($instanceId, $failedRunId, [ | `definition_incompatible_with_prefix` | 修正后的代码无法重放已完成的步骤。`definition_mismatch` 指出第一个不同的步骤。 | | `definition_check_over_budget` | 已完成的历史超出了重放检查允许的历史预算。 | | `definition_change_requires_replay_check` | 运行由服务模式 Worker 启动,因此 redrive 无法检查已变更的定义。 | -| `service_redrive_history_not_qualified` | 运行由服务模式 Worker 启动,且失败之前的步骤包含备忘录 upsert、搜索属性 upsert、信号等待或已应用的更新。在能够针对每个 SDK 运行时检查其能否重放这些步骤之前,redrive 会在服务模式运行中拒绝这些步骤。 | +| `service_redrive_history_not_qualified` | 运行由服务模式 Worker 启动,且失败之前的步骤包含备忘录 upsert、搜索属性 upsert、信号等待、已应用的更新或已完成的子工作流调用。在能够针对每个 SDK 运行时检查其能否重放这些步骤之前,redrive 会在服务模式运行中拒绝这些步骤。 | | `request_id_already_used` | 该 `request_id` 已用于该实例的另一次 redrive。 | | `already_redriven` | 对于已经被 redrive 过的运行,由运行详情和 `describe()` 报告。对它发起的 redrive 请求会改为返回现有的后继运行。 | | `invalid_request_id` | `request_id` 超过 191 个字符。 | @@ -242,6 +249,8 @@ $result = app(WorkflowControlPlane::class)->redrive($instanceId, $failedRunId, [ ### 更早的版本与原生 Server {#redrive-earlier-releases} +2.26.0 之前的 Workflow 版本会以 `unsupported_history` 拒绝历史中的任何子工作流。它们会忽略子工作流事件上的 `reused_recorded_at`,因此复用过子工作流调用的 2.26.0 后继运行在这些版本上重放时,该调用之后的工作流时间以及截止时间可能不同。它们还会拒绝再次对其 redrive。一旦存在这样的后继运行,请继续使用 2.26.0 或更高版本的 Worker,或在回滚前确认没有这样的历史会被重放。 + Workflow 2.20.0 不会拒绝任何 2.20.1 接受的内容。在 2.20.0 中,复用的工作流代码里的 `outbox()->sendReference()` 会再次发送,而重放的 `inbox()->receive()` 可能返回不同的消息或什么都不返回,也可能消费一条更新的消息([workflow#1010](https://github.com/durable-workflow/workflow/issues/1010))。 Workflow 2.19.0 会拒绝已应用的更新(`unsupported_history`)。它还会拒绝对复用过更新(`unsupported_history`)或信号等待(`mismatched_signal_receipt`)的后继运行进行 redrive。运行详情和 `describe()` 会把 redrive 链接显示为诊断用的回退。 diff --git a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/features/child-workflows.md b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/features/child-workflows.md index 2bbf6fe1b9d..fa45af3b59a 100644 --- a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/features/child-workflows.md +++ b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/features/child-workflows.md @@ -200,7 +200,7 @@ $results = all([ - 父运行因任意原因关闭时,引擎查询策略不是 abandon 的未完成子链接,并向每个未完成子工作流发送相应命令:请求协作取消、取消或终止。 - 执行策略时子工作流若已关闭,则不执行任何操作,静默跳过命令。 - 策略以尽力而为方式执行:子命令被拒绝(例如子工作流已终态)不影响父级关闭。执行成功时在父运行记录 `ParentClosePolicyApplied` 历史事件;失败时改为记录 `ParentClosePolicyFailed`,使运维人员能区分成功执行与静默失败。 -- continue-as-new **不会**触发父级关闭策略,因为工作流实例仍在新运行中保持活动。 +- continue-as-new **不会**触发父级关闭策略,因为工作流实例仍在新运行中保持活动。自 Workflow 2.26 起,改由链中的最终运行应用该策略。参见[继续为新运行与未关闭的子工作流](#continue-as-new-and-open-children)。 ### 父级结果矩阵 {#parent-disposition-matrix} @@ -213,9 +213,21 @@ $results = all([ | 超时 | 是 | 运行超时或执行超时关闭记录 `WorkflowTimedOut` 后触发。 | | 已取消 | 是 | 已接受的 `CancelRequested` 命令关闭父运行后触发。 | | 已终止 | 是 | 已接受的 `TerminateRequested` 命令关闭父运行后触发。 | -| 继续为新运行 | 否 | 工作流实例在新运行中保持活动,现有子链接改为指向新运行,并保留原始策略。 | +| 继续为新运行 | 否 | 工作流实例在新运行中保持活动。自 Workflow 2.26 起,继续运行接管对未关闭子工作流的监管,并由链中的最终运行应用它们的策略。 | | 重置 | 目前不适用 | v2 运行时未提供独立重置命令或重置终态结果。未来关闭或替换父运行的重置或修复操作,必须明确子所有权是否转移;旧运行若成为终态,必须在停止持有未完成子工作流前应用父级关闭策略。 | +### 继续为新运行与未关闭的子工作流 {#continue-as-new-and-open-children} + +在 Workflow 2.26 及更高版本中,父工作流在其启动的子工作流仍未关闭时继续为新运行,会在同一事务中把这些子工作流交给继续运行。嵌入式运行和服务模式运行的行为相同: + +- 每个未关闭的子工作流会在 `workflow_child_supervisions` 表中获得一行,该表由 2.26 迁移创建。已关闭的子工作流不会被交接。 +- 子链接、子调用、序号、截止时间和父级关闭策略保持启动运行记录时的状态。当继续运行再次继续为新运行时,会再次交接这些子工作流。 +- 当链中的最终运行完成、失败、超时、被取消或被终止时,它会对每个子工作流应用其策略,并在自身历史中记录 `ParentClosePolicyApplied` 或 `ParentClosePolicyFailed`。`abandon` 仍为 `abandon`。已关闭的较早运行不会获得新的历史。 +- 继续运行没有这些子工作流的句柄,它们的结果也不会传递给继续运行。下一个运行需要的任何内容,请通过 `continueAsNew()` 的参数传递。 +- 被交接的子工作流失败时,只要链中仍有运行在监管它,就会按启动运行记录的重试策略重试,并保持相同的子调用标识和尝试次数。重试运行的 `WorkflowStarted` 将启动运行列为其父运行,链中的最终运行会对重试运行应用父级关闭策略。尝试次数耗尽、失败不可重试或链已关闭时,失败即为最终结果。 + +在 2.26 之前,这些子工作流会在链关闭后继续运行,其策略从未被应用;父工作流继续为新运行之后失败的子工作流也不会被重试。参见 [2.26.0 发布说明](https://github.com/durable-workflow/workflow/releases/tag/2.26.0)。 + ### 各策略的使用场景 {#when-to-use-each-policy} **放弃管理(Abandon)**是默认策略,适用于子工作流代表独立工作,无论父级结果如何都应完成的情况,例如通知工作流或必须完成的清理任务。 diff --git a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/features/continue-as-new.md b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/features/continue-as-new.md index 2c2c9c7b387..985700d7b85 100644 --- a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/features/continue-as-new.md +++ b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/features/continue-as-new.md @@ -70,6 +70,10 @@ Core 2.7.0 和兼容 Server 会保留已收到、由运行命令契约声明处 工作流代码可通过显式运行时上下文读取当前历史长度和继续为新运行的建议标记,让长期循环在触及历史预算边界之前主动交接。 +在 Workflow 2.26 及更高版本中,请使用 `shouldContinueAsNewAtStep()` 和 `historyBudgetAtStep()`。它们只统计当前工作流步骤之前记录的历史,因此同一行代码在每次重放时都返回相同的结果。在每次迭代中检查预算的循环,只会在第一次超过阈值的迭代处继续为新运行一次。 + +旧方法读取的是整个当前历史。在循环中,较早的迭代在重放时可能看到较晚的总量,从而走上与第一次不同的分支。这些方法没有变化,因此已经用它们做出决定的运行仍可继续重放。 + ```php use function Workflow\V2\activity; use function Workflow\V2\continueAsNew; @@ -97,6 +101,8 @@ class PollingWorkflow extends Workflow | `$this->historyLength()` | `int` | 当前运行的历史事件数 | | `$this->historySize()` | `int` | 历史事件的总字节数 | | `$this->shouldContinueAsNew()` | `bool` | 运行超过配置的事件数量或字节大小预算时为 `true` | +| `$this->historyBudgetAtStep()` | `array` | 截至当前步骤的预算:`history_event_count`、`history_size_bytes`、`history_fan_out`、`continue_as_new_recommended`、`pressure`、`pressure_dimensions` 和 `observation`(`step_prefix.v1`)。Workflow 2.26 及更高版本。 | +| `$this->shouldContinueAsNewAtStep()` | `bool` | 来自 `historyBudgetAtStep()` 的 `continue_as_new_recommended`。请在循环中使用。Workflow 2.26 及更高版本。 | ### 配置 {#configuration} @@ -112,7 +118,7 @@ class PollingWorkflow extends Workflow ], ``` -任一阈值被超过时,`shouldContinueAsNew()` 返回 `true`。运行摘要也跟踪 `history_event_count`、`history_size_bytes` 和 `continue_as_new_recommended`,便于 Waterline 在集群视图中标记长期运行。 +任一阈值被超过时,`shouldContinueAsNew()` 和 `shouldContinueAsNewAtStep()` 返回 `true`。运行摘要也跟踪 `history_event_count`、`history_size_bytes` 和 `continue_as_new_recommended`,便于 Waterline 在集群视图中标记长期运行。 ## 元数据继承 {#metadata-carry-forward} @@ -152,4 +158,6 @@ class PollingWorkflow extends Workflow } ``` +父工作流在其启动的子工作流仍未关闭时继续为新运行,会把这些子工作流交给继续运行。参见[继续为新运行与未关闭的子工作流](./child-workflows.md#continue-as-new-and-open-children)。 + 长期运行的人类输入或助手循环,优先使用正式的 `$this->inbox()` / `$this->outbox()` [消息流](./message-streams.md)门面。待处理的流消息和游标位置会转移到新运行,已消费消息留在原运行,作为历史证据。Workflow 2.20.1 及之前的版本会把待处理的流消息留在已关闭的运行上([workflow#1018](https://github.com/durable-workflow/workflow/issues/1018),已在 2.20.2 中修复);参见[消息流](./message-streams.md#continue-as-new)。 diff --git a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/features/search-attributes.md b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/features/search-attributes.md index 108b6cb7b00..285447a7ab0 100644 --- a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/features/search-attributes.md +++ b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/features/search-attributes.md @@ -105,7 +105,7 @@ $controlPlane->start('orders.process-order', 'order-42', [ 注册只约束你注册的键。从原生 Server 3.5.0 起,未注册的键仍会被接受,其类型会被推断,与没有注册属性的 namespace 相同。注册一个属性不会破坏正在运行、upsert 其他键的工作流。PHP Server 2.x 和 3.5.0 之前的原生 Server 在注册任何属性后都会拒绝所有未注册的键,因此在这些版本上,请先注册工作流使用的所有键,再注册第一个属性。 -删除注册后将不再校验该键。已存储的值和正在运行的工作流不会改变,之后对该键的 upsert 会重新推断类型。 +删除注册后将不再校验该键。已存储的值和正在运行的工作流不会改变,之后对该键的 upsert 会重新推断类型。在原生 Server 上,按未注册的键(包括已删除注册的键)过滤的列表查询会被拒绝,因为该键未在 namespace 中定义。 要更改属性的类型,请用新类型注册一个新的属性名,更新工作流以写入该名称,并在现有运行跟上后按新名称过滤。删除同一名称后再以不同类型重新注册,之前的值仍保留旧类型。 diff --git a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/polyglot/php.md b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/polyglot/php.md index 020285b7019..ce6cf46ae72 100644 --- a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/polyglot/php.md +++ b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/polyglot/php.md @@ -197,7 +197,7 @@ PHP `^8.1`、Laravel 桥接的下限、worker 协议 `1.20` 和控制平面 `2` - **Sticky 历史后缀(3.14)。** Worker 声明 `sticky_history_suffix`。在 Server 3.5.0 或更高版本上,已持有某个运行历史的 worker 只接收其缓存序列之后的事件。不能精确接续缓存历史的后缀会被丢弃,并重新获取完整历史。旧版 Server 仍发送完整历史。 - **计划来源(3.13)。** `WorkflowContext::scheduleOrigin()` 返回启动该运行的计划触发的计划 id、发生时间和触发编号;普通启动返回 `null`。重放时该值相同。自 Server 3.5.0 起,以 continue-as-new 继续的运行会保留其计划来源。 -- **活动续接(3.12)。** 当 Server 声明 `activity_workflow_continuation`(原生 Server 3.4.0 或更高版本)时,向 `Worker` 构造函数传入 `enableActivityContinuation: true`,即可把下一批工作流命令与成功的活动结果一起提交。默认值为 `false`。如果启用,请使用 3.12.1 或更高版本,并在降级 Server 或加入旧版 Server 节点之前排空或停用这些 worker。 +- **活动续接(3.12)。** 当 Server 声明 `activity_workflow_continuation`(原生 Server 3.4.0 或更高版本)时,向 `Worker` 构造函数传入 `enableActivityContinuation: true`,即可把下一批工作流命令与成功的活动结果一起提交。默认值为 `false`。目前启用它会降低吞吐量:在我们的负载基准测试中,启用后工作流运行慢了 24–49%,数据库事务数量是原来的两倍([测量](https://github.com/durable-workflow/server/issues/1078))。如果启用,请使用 3.12.1 或更高版本,并在降级 Server 或加入旧版 Server 节点之前排空或停用这些 worker。 完整列表请参见 [3.14.0 变更日志](https://github.com/durable-workflow/sdk-php/blob/3.14.0/CHANGELOG.md)。 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 c76fe2bd204..62bae5f3732 100644 --- a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/testing.md +++ b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/testing.md @@ -350,7 +350,7 @@ public function testReturnExistingActiveStart(): void ### 测试历史预算 {#testing-history-budget} -`HistoryBudget` 字段(`history_event_count`、`history_size_bytes`、`continue_as_new_recommended`)通过运行摘要投影公开,并可由 `RunDetailView` 获取。工作流代码中,`Workflow` 基类以 `$this->historyLength()`、`$this->historySize()` 和 `$this->shouldContinueAsNew()` 公开这些值: +`HistoryBudget` 字段(`history_event_count`、`history_size_bytes`、`continue_as_new_recommended`)通过运行摘要投影公开,并可由 `RunDetailView` 获取。工作流代码中,`Workflow` 基类以 `$this->historyLength()`、`$this->historySize()` 和 `$this->shouldContinueAsNew()` 公开这些值。在循环中,请使用 `$this->shouldContinueAsNewAtStep()`(Workflow 2.26 及更高版本),它在每次重放时都给出相同的结果: ```php use Workflow\V2\Workflow; @@ -362,7 +362,7 @@ final class LongRunningWorkflow extends Workflow while (true) { // ... process work ... - if ($this->shouldContinueAsNew()) { + if ($this->shouldContinueAsNewAtStep()) { Workflow::continueAsNew($this->carryForwardState()); } } diff --git a/i18n/zh-Hans/source-hashes.json b/i18n/zh-Hans/source-hashes.json index aaa9e3d33f5..29802b30c7c 100644 --- a/i18n/zh-Hans/source-hashes.json +++ b/i18n/zh-Hans/source-hashes.json @@ -4,7 +4,7 @@ "ai-agent-workflow-engine.md": "28016466b179adbabdff6467ce351100c9bee48529a8bec9df7ec22c8d786d4d", "ai-assisted-development.md": "b246bb60585fb7a69bc534978f470f3f16e899e1f8f203ba0847d2d11b8a1ec3", "capabilities.md": "d9a2bbc0d04adf8cb3f4c7f42d779a43aafab60791210305e7e476c0499528fc", - "compatibility.md": "567310faf420fbd5229c5eef69721e8b7d09f033333cbaec21b72acaf81b6690", + "compatibility.md": "ad5c8519be03ae1e7b6e5e03b05a886862fd67c603b241ecb5baf2be5cd59610", "configuration/customization-matrix.md": "3d115863eaee7852b541bcd01615f424cc19c5847c7cd7d75e5ae63bc3f5cc78", "configuration/database-connection.md": "cc83ae77133236309506fa44d39bfd0c939c32a6154c0bd6099bc64c83bdaec9", "configuration/ensuring-same-server.md": "6c665f37cc198c7b1a775a60a94aab5ff4e55383385e76f1834c7840559b512a", @@ -24,18 +24,18 @@ "defining-workflows/activities.md": "05b46f73477a0bbd5f21d17ac37def8a8eac53f1e629155805c98cc46e75b418", "defining-workflows/passing-data.md": "c5d36126b0b15f1780119f6418e8bbe5a63e03353be5a0bb69385206ef0ad635", "defining-workflows/starting-workflows.md": "722b80454b577b0715ff50db70c7cda2cd02c34c505dd1219a83307852d325a4", - "defining-workflows/workflow-api.md": "a6150e75302323b49f350159ce3568a51a19701bb81829915615f754592ee79c", + "defining-workflows/workflow-api.md": "3c13894c1fdbe77bb1379c62bbdb0ef213c81f1cba5b477d45402dcc7fe87237", "defining-workflows/workflow-id.md": "ca3b43253a748b27dca1af9f82fcf8c4c133e14f13e1b82eaa1ca2ed0996d4bf", "defining-workflows/workflow-status.md": "8e8cb27ff44c890d489d89bf166375acfdfaecabd990a2235e106fab1592d529", "defining-workflows/workflows.md": "f467bc73de32aa5d722c61ce085065460382ae7dd44cea4625847d9fcdc4c97c", "deployment.md": "6aa439b1ebfdc2affccaf6fe6fff7519776a4ffcad8d3cb5956b665e7c97257f", - "failures-and-recovery.md": "598b538e2bcb6a40a4f2d4c0c462705bab30ef96767144f6590c2cc93b68a98a", + "failures-and-recovery.md": "4209521a8783939d458658a7afea64124c34571080c97feb2868a273db88db3e", "features/activity-execution-model.md": "e8c37520ae46a7efb30438f4fc06bf893c1df430cb1f92c48963697adaf09082", "features/cancel-and-terminate.md": "cedd1e6c51dfa551e00edc1d39739ff1f67d558d2a0be92143f478cb6111536b", - "features/child-workflows.md": "57016591fb8816aed7b077e204f1c80f9c6a8dff7501bc00a141c41a4607306b", + "features/child-workflows.md": "278b634b8b48b94203309cdba27d6116897a2919cab19628add8cd85dadb08d3", "features/concurrency.md": "a7a3eb2274f7b14faf722494569b7663c07ab48afdf2e9225e58914b84cacbb4", "features/condition-waits.md": "451261eda990c9591a0db69839d872184b5c64da6b537a582133095b8d4b599e", - "features/continue-as-new.md": "50c79f317155e052a3f2f37d198a71bdfc496a454905293f40cf09d73138f25b", + "features/continue-as-new.md": "a5309192c685abeb5295071d423824ae2287e68d247a6661f18d3ab21f9bdc9c", "features/events.md": "c466df05908748489226a3d1410c9203cf6f2986a4bb7539db1c5f82715abc7b", "features/external-payload-storage.md": "acc312fa2f50a43c96e1d235439124d28a7048f0bf3abac34319467fcbf7e898", "features/heartbeats.md": "4fce9636d68c89f29f259d52e463cd67eccf0bc55ad4d53338ed03329892b365", @@ -45,7 +45,7 @@ "features/queries.md": "c66dd9542a062edd8158a46cebc9f1bf926aaf3599dca4a3122bd9860df6e2a2", "features/sagas.md": "046ba5661ccb5ac71a236356d243b021d9830123e3798afce491118434e83820", "features/schedules.md": "40d30b2767e7ed043e2b0c7180915c256accea3e7a3401c38d1bf75bfe1c2213", - "features/search-attributes.md": "567d89858cd82e86672b210154001a272b17a5f87e13dbfa7de1b8e093d615b8", + "features/search-attributes.md": "bb66d83f64e0098354d86ac237e6867b9819098044101ba9a60a6a00a3961dd1", "features/service-operations.md": "912131c0a8ef393040a933fb4a66e68abcb9d475a3ebd47c85287d4032f45a0e", "features/side-effects.md": "abdccab8d6fc1a12b3eff8a4ccc58730ac36f523559b4ad89c5c2a8d201a3b86", "features/signal+timer.md": "a05fc480544fa71f6c9b215ad3417f71b8475dd81f9de8ee18d7a3b69ac33a23", @@ -80,7 +80,7 @@ "polyglot/invocable-carrier.md": "d32d8b5c7c33204b342f977e0af734166d91e96073db1a49ccb4d414a6d67380", "polyglot/invocable-php-handler.md": "3b678eb1d69fe32dfcfdc05d36b33e49e01b79d7216bd784f6a61a6f1c3c3a13", "polyglot/namespace-auth-workers.md": "2b4078ceb74b849f12cb1975b410ff8e7266cd4345f6cf1d4dd906db12460ffb", - "polyglot/php.md": "04f7eeebf842bbcd2f278f96ee21fbbf4f97d424a27e717d65e1c73273bce095", + "polyglot/php.md": "309e83622754b9d9abc65807280f2dab175a009054a001456ef1316776f11101", "polyglot/polling-patterns.md": "30875099a23731c6c471b481a771378acc6ff57eed2fda4405a509057534c989", "polyglot/portable-worker-affinity.md": "40973c6a31a76845b4f95e9a505e68ad76abd5174bbdccf37993cdebc8904959", "polyglot/prerelease-history-migration.md": "a57f05f492228a8a67791f9152648a1e5f80856325b78777cf63b6ef49b7413c", @@ -105,6 +105,6 @@ "sdk-neutrality.md": "7b0714c123ade4904591870fc20e9a797da1e5485b2a6c87ca3eaa00c5de6ed6", "sponsors.md": "e85e14375743ca8fa50e3a48f894b160e28272573aa88480064f74010ebee98a", "support.md": "706807b3902599dda6080f632ec1f893017ea18bbe9585f533dcdbd6d85f4621", - "testing.md": "250bc7dfd46f99eaeb392b329947813b064bda72026645198e3aefc80043a813", + "testing.md": "176abf226936c7711c2df523fb8a94e92fcf62e6f804d99f2e32b9135f626547", "waterline-operator-api.md": "2aca03b2c14100060b40be0bb033a82525ba924908834e9060ec746ead26f36d" } diff --git a/static/stable-releases.json b/static/stable-releases.json index fb04bedbdea..bbb88ea6717 100644 --- a/static/stable-releases.json +++ b/static/stable-releases.json @@ -10,7 +10,7 @@ "sdk-rust": "4.14.0", "server": "3.7.0", "waterline": "2.17.0", - "workflow": "2.25.0" + "workflow": "2.26.0" }, "helm_chart": { "app_version": "3.7.0",