From 0abd39c761aa0074964020bac0124d467a340571 Mon Sep 17 00:00:00 2001 From: Albert Callarisa Date: Wed, 3 Jun 2026 10:29:22 +0200 Subject: [PATCH 1/2] Document timer origin Signed-off-by: Albert Callarisa --- .../workflow-protocol-execution-api.md | 17 +++++++++++++---- .../workflow-protocol-state-and-history.md | 4 +++- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/daprdocs/content/en/contributing/protocol-reference/workflow-protocol/workflow-protocol-execution-api.md b/daprdocs/content/en/contributing/protocol-reference/workflow-protocol/workflow-protocol-execution-api.md index e34fa105fa3..51191620c30 100644 --- a/daprdocs/content/en/contributing/protocol-reference/workflow-protocol/workflow-protocol-execution-api.md +++ b/daprdocs/content/en/contributing/protocol-reference/workflow-protocol/workflow-protocol-execution-api.md @@ -8,7 +8,7 @@ description: "Low-level description of the Workflow building block internals." # Workflow Execution API (Task Hub Protocol) -The Workflow Execution API is a low-level gRPC protocol used by Dapr Workflow SDKs to act as "Workers". The SDK +The Workflow Execution API is a low-level gRPC protocol used by Dapr Workflow SDKs to act as "Workers". The SDK connects to the Dapr sidecar via this protocol to poll for work and report completion. The service is named `TaskHubSidecarService`. @@ -81,7 +81,7 @@ Reports the result of an activity execution. ### HistoryEvent -Workflows in Dapr are event-sourced. The state of an orchestration is rebuilt by replaying a sequence of +Workflows in Dapr are event-sourced. The state of an orchestration is rebuilt by replaying a sequence of `HistoryEvent` messages. Common event types: @@ -93,6 +93,15 @@ Common event types: * `TimerFired`: A timer expired. * `OrchestrationCompleted`: The workflow finished. +#### Timer origin + +`TimerCreated` events record an `origin` that identifies why the timer was scheduled. This is internal engine bookkeeping (also surfaced by the `dapr workflow history` command); it does not change how workflows author or use timers. The possible origins are: + +* `createTimer`: An explicit durable timer created by the workflow (for example, `ctx.create_timer(...)`). +* `externalEvent`: A timer backing a "wait for external event" call that has a timeout. Carries the event name. +* `activityRetry`: A timer backing the delay between activity retry attempts. Carries the failing task's execution ID. +* `childWorkflowRetry`: A timer backing the delay between child-workflow retry attempts. Carries the child instance ID. + ### FailureDetails Used to report errors from activities or orchestrations. @@ -104,7 +113,7 @@ Used to report errors from activities or orchestrations. ## Protocol Nuances * **Streaming**: `GetWorkItems` is a server-to-client stream. Dapr pushes work to the SDK as it becomes available. -* **Sticky Sessions**: Dapr attempts to send work items for the same instance to the same worker if possible, but +* **Sticky Sessions**: Dapr attempts to send work items for the same instance to the same worker if possible, but the SDK must not rely on this for correctness. -* **Determinism**: The SDK **must** ensure that the orchestration logic is deterministic. During replay, the SDK +* **Determinism**: The SDK **must** ensure that the orchestration logic is deterministic. During replay, the SDK uses the history provided in the `OrchestratorWorkItem` to avoid re-executing actions that have already been recorded. diff --git a/daprdocs/content/en/contributing/protocol-reference/workflow-protocol/workflow-protocol-state-and-history.md b/daprdocs/content/en/contributing/protocol-reference/workflow-protocol/workflow-protocol-state-and-history.md index 374e2f4299b..521538fce1a 100644 --- a/daprdocs/content/en/contributing/protocol-reference/workflow-protocol/workflow-protocol-state-and-history.md +++ b/daprdocs/content/en/contributing/protocol-reference/workflow-protocol/workflow-protocol-state-and-history.md @@ -39,7 +39,9 @@ A sequence of `HistoryEvent` objects that record everything that has happened in To optimize for large histories, Dapr often stores history events in chunks or as separate keys in the state store: * **Key Format**: `wf-history--` * **Event Content**: Serialized protobuf message containing event type, timestamp, and type-specific data (e.g., - `TaskScheduled`, `TaskCompleted`). + `TaskScheduled`, `TaskCompleted`). Some event types carry additional type-specific fields — for example, + `TimerCreated` events record an `origin` that identifies why the timer was scheduled (see + [Execution API]({{% ref "workflow-protocol-execution-api.md" %}})). ### 3. Inbox (Pending Events) A collection of events that have occurred but have not yet been processed by the orchestrator (replayed). This includes: From 99bccd0fd9b395c09b40f183eb15fd4e2a951ac0 Mon Sep 17 00:00:00 2001 From: Albert Callarisa Date: Wed, 3 Jun 2026 15:52:00 +0200 Subject: [PATCH 2/2] Address comments Signed-off-by: Albert Callarisa --- .../workflow-protocol/workflow-protocol-execution-api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daprdocs/content/en/contributing/protocol-reference/workflow-protocol/workflow-protocol-execution-api.md b/daprdocs/content/en/contributing/protocol-reference/workflow-protocol/workflow-protocol-execution-api.md index 51191620c30..95cbbef322c 100644 --- a/daprdocs/content/en/contributing/protocol-reference/workflow-protocol/workflow-protocol-execution-api.md +++ b/daprdocs/content/en/contributing/protocol-reference/workflow-protocol/workflow-protocol-execution-api.md @@ -95,7 +95,7 @@ Common event types: #### Timer origin -`TimerCreated` events record an `origin` that identifies why the timer was scheduled. This is internal engine bookkeeping (also surfaced by the `dapr workflow history` command); it does not change how workflows author or use timers. The possible origins are: +`TimerCreated` events record an `origin` that identifies why the timer was scheduled. This is internal engine bookkeeping (also surfaced by the `dapr workflow history` command); it does not change how developers author workflows or how timers behave. The possible origins are: * `createTimer`: An explicit durable timer created by the workflow (for example, `ctx.create_timer(...)`). * `externalEvent`: A timer backing a "wait for external event" call that has a timeout. Carries the event name.