From b762482a501d7c35e60e38414a3cdb0f117dc6ff Mon Sep 17 00:00:00 2001 From: Richard McDaniel <1130888+rmcdaniel@users.noreply.github.com> Date: Fri, 13 Nov 2026 02:56:09 +0000 Subject: [PATCH] Prepare Workflow 2.28.0 product metadata and release notes Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 37 ++++++++++++++++++++++--------------- composer.json | 2 +- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 71ff4a48..769aa002 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,22 +2,12 @@ ## Unreleased -- Replaying a workflow that repeats the same message-stream send no longer - lists every earlier matching row again for each send (#1014). The exactly - matched candidates for a send identity are now loaded once per execution - and extended with the rows that execution writes, so N identical sends in - one replay cost one candidate query instead of N, and O(N) rows instead of - O(N²). Matching is unchanged: exact field comparison, send order and the - redrive chain. +## 2.28.0 - 2026-11-13 -- An expired open activity row of a closed run is now closed instead of being - selected and skipped on every timeout sweep (#1117 follow-up). An activity - that its run's close left running under the abandon policy is marked failed - when its own `schedule_to_close` deadline passes without an outcome. Any - other open row of a closed run, such as one left by a close before - upgrading, is cancelled. Its task is cancelled and nothing is appended to - the closed run's history. Before, such rows stayed open and could fill the - sweep's batch limit. +**Behavior change:** an un-awaited `select()` loser is cancelled when the run +closes. To keep a service-mode activity running, schedule it with +`cancellation_policy: abandon`; its outcome is then never recorded. See the +first entry below. No migration. - A run no longer leaves work running after its own code closes it (#1117). Before, an activity or timer the workflow never awaited, such as a @@ -41,6 +31,23 @@ Behavior change: if a workflow needs a loser's effect, await the loser before returning. +- Replaying a workflow that repeats the same message-stream send no longer + lists every earlier matching row again for each send (#1014). The exactly + matched candidates for a send identity are now loaded once per execution + and extended with the rows that execution writes, so N identical sends in + one replay cost one candidate query instead of N, and O(N) rows instead of + O(N²). Matching is unchanged: exact field comparison, send order and the + redrive chain. + +- An expired open activity row of a closed run is now closed instead of being + selected and skipped on every timeout sweep (#1117 follow-up). An activity + that its run's close left running under the abandon policy is marked failed + when its own `schedule_to_close` deadline passes without an outcome. Any + other open row of a closed run, such as one left by a close before + upgrading, is cancelled. Its task is cancelled and nothing is appended to + the closed run's history. Before, such rows stayed open and could fill the + sweep's batch limit. + ## 2.27.0 - 2026-11-13 - Closing a child no longer reads every sibling's history under the parent diff --git a/composer.json b/composer.json index 517dfe07..75d44fea 100644 --- a/composer.json +++ b/composer.json @@ -87,7 +87,7 @@ "dev-main": "2.0.x-dev" }, "durable-workflow": { - "product-train": "2.27.0", + "product-train": "2.28.0", "laravel-embedded-upgrade-contract": "resources/laravel-embedded-upgrade-contract.json", "laravel-dependency-security-policy": "resources/laravel-dependency-security-policy.json" },