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
24 changes: 17 additions & 7 deletions docs/portal/build/failures-retries.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ next:
| `NonDeterministicWorkflow` | Code no longer matches committed history. | Restore compatible code; do not blindly retry. |
| `WorkflowFailed` | The execution closed as failed. | Surface the recorded failure to the caller. |
| `WorkflowTimedOut` | A Server deadline closed the run. | Start a new workflow only if business policy permits. |
| `WorkflowCancelled` / `WorkflowTerminated` | Both close the Server run immediately, with distinct terminal reasons. | Do not expect workflow-code cleanup after either command. |
| `WorkflowCancelled` | The run closed as Cancelled, after terminal cancellation or successful cooperative cleanup. | Inspect the cancellation lifecycle and cleanup outcome. |
| `WorkflowTerminated` | Termination closed the run immediately. | Do not expect workflow-code cleanup after termination. |

## Make activity retries safe

Expand Down Expand Up @@ -51,12 +52,16 @@ from history. Discarding a suspended replay Fiber does not schedule cleanup or
complete the workflow; PHP may still unwind local `finally` code, so put external
effects in activities rather than directly in the workflow body.

Do not use `finally` as a guarantee against terminal `cancelWorkflow()`,
`terminateWorkflow()`, process death, or an already closed run. Service-mode
Server does not yet expose the separate cooperative cancellation request
available to embedded Laravel. When business cancellation requires
compensation to finish, signal that intent and let the workflow complete its
cleanup before closing the run.
Use `requestCancellation()` with cooperating workers when cancellation requires
bounded workflow cleanup. The request preserves one original deadline across
children, activities, duplicates and worker replacement. Shielded durable
cleanup replays after worker loss and successful cleanup closes the run as
`Cancelled`. See the [cooperative cancellation guide](https://durable-workflow.com/docs/2.0/polyglot/cancellation/)
for worker opt-in, operation policies and inspection.

Terminal `cancelWorkflow()` and `terminateWorkflow()` still close the run
immediately. They do not resume workflow cleanup, and an already closed run
cannot schedule compensation through `finally`.

## Heartbeat long attempts

Expand All @@ -69,6 +74,11 @@ foreach ($batches as $index => $batch) {

Heartbeat details make slow work observable and provide a cancellation checkpoint. Catch `ActivityCancelled` only to release local resources, then rethrow it so the runtime records cancellation correctly.

Cooperative workers supervise callbacks independently of application
heartbeats. A stop receipt proves callback stop, while attempt fencing rejects
a stale result. Downstream side effects still need application idempotency or
reconciliation.

## Preserve terminal distinctions at the client

```php
Expand Down
4 changes: 4 additions & 0 deletions docs/portal/build/workflows-activities.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,10 @@ try {

`ActivityContext::heartbeat()` records progress and throws `ActivityCancelled` when the Server requests cancellation. Heartbeat before and during long calls that can be safely divided into chunks.

Workers that opt into [cooperative cancellation](https://durable-workflow.com/docs/2.0/polyglot/cancellation/)
supervise callbacks and observe cancellation independently of application
heartbeats. Prepared local activities use supervised callback processes.

## Use durable commands for workflow time

The context provides these replay-aware commands:
Expand Down
Loading