Skip to content

Commit 627700a

Browse files
durable-workflow.github.io: update v2 changes
1 parent b2a9249 commit 627700a

File tree

3 files changed

+30
-1
lines changed

3 files changed

+30
-1
lines changed

docs/features/child-workflows.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ $results = all([
197197
- The policy is recorded on the `workflow_links` row (`parent_close_policy`) and in the `ChildWorkflowScheduled` history event payload.
198198
- When the parent run closes for any reason, the engine queries open child links with a non-abandon policy and sends the appropriate command (cancel or terminate) to each open child.
199199
- If the child has already closed by the time the policy is enforced, no action is taken — the command is silently skipped.
200-
- 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.
200+
- 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.
201201
- Continue-as-new does **not** trigger parent-close policy, because the workflow instance remains active under a new run.
202202

203203
### When to use each policy

docs/features/timeouts.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,25 @@ When a workflow continues as new:
104104

105105
This means the execution timeout always measures from the original start, while each new run gets its own fresh run-timeout window.
106106

107+
## Enforcement
108+
109+
Workflow-level timeouts are enforced at two points:
110+
111+
1. **At workflow task start** — every workflow task checks `deadlineExpired()` before executing the workflow. If the deadline has passed, the run is immediately timed out.
112+
2. **By the TaskWatchdog** — the watchdog scans for non-terminal runs whose execution or run deadline has passed but that have no open workflow task. When found, it creates a deadline-expired workflow task and dispatches it, which triggers the timeout on the next task execution.
113+
114+
When a timeout fires, the engine:
115+
116+
- Cancels all open tasks (activity, timer, workflow) except the current one
117+
- Cancels all open activity executions with `ActivityCancelled` history events
118+
- Cancels all pending timers with `TimerCancelled` history events
119+
- Records a `WorkflowFailure` with `failure_category = timeout` and a `WorkflowTimeoutException`
120+
- Records a terminal `WorkflowTimedOut` history event with `timeout_kind` set to `execution_timeout` or `run_timeout`
121+
- Applies parent-close policy to any open child workflows
122+
- Notifies parent workflows if this was a child run
123+
124+
The failure row stores `Workflow\V2\Exceptions\WorkflowTimeoutException` as the exception class, carrying the `timeout_kind` and the deadline timestamp for programmatic inspection.
125+
107126
## Activity timeouts
108127

109128
Activity timeouts let you bound how long individual activity executions are allowed to take. There are four activity timeout scopes:

docs/features/timers.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,14 @@ Timer behavior:
3636
- Waterline surfaces timer waits in run detail and dashboard payloads
3737
- engine-level `cancel()` and `terminate()` commands supersede open timer waits durably, and late timer jobs no-op instead of reopening the run
3838

39+
### Transport chunking
40+
41+
Some queue drivers impose a maximum delay on initial message delivery. For example, Amazon SQS caps `DelaySeconds` at 900 seconds (15 minutes). When a timer's duration exceeds the queue driver's limit, the engine automatically chunks the delay:
42+
43+
1. The timer task is dispatched with the driver's maximum delay instead of the full duration.
44+
2. When the task arrives early (before `fire_at`), it re-releases itself with the remaining delay.
45+
3. This relay continues until the timer's actual fire time is reached.
46+
47+
This is transparent to the workflow — the timer row still records the full duration and the correct `fire_at` timestamp. The chunking happens purely at the transport layer. For SQS, subsequent relay hops can use up to 43,200 seconds (12 hours) via `ChangeMessageVisibility`, so most timers complete in one or two hops.
48+
3949
`sideEffect()` is available for replay-safe snapshots such as randomness or one-time branch inputs. A dedicated `Workflow\V2\now()` and unit-helper API is still evolving, so `timer()` remains the only time suspension helper today.

0 commit comments

Comments
 (0)