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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 22 additions & 15 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
},
Expand Down
Loading