Skip to content

Add support for workflow history propagation #1001

@cicoyle

Description

@cicoyle

Background

Dapr Workflows now supports propagating execution history from a parent workflow to its child workflows and activities. This lets downstream code inspect what happened upstream — useful for chain-of-custody verification, fraud detection, audit, and AI-agent context flow.

Two scopes are exposed:

  • PropagateLineage — caller's own events plus the full ancestor chain
  • PropagateOwnHistory — caller's events only (a trust boundary; ancestors are dropped)

The Go path is implemented end-to-end. To use this feature from a Python app, this SDK needs the matching API.

Proto surface

From dapr/durabletask-protobuf (PR #38):

  • history_events.proto
    • TaskScheduledEvent.historyPropagationScope (optional, field 7)
    • ChildWorkflowInstanceCreatedEvent.historyPropagationScope (optional, field 7)
    • new PropagatedHistory { repeated HistoryEvent events; HistoryPropagationScope scope; repeated PropagatedHistoryChunk chunks; }
    • new PropagatedHistoryChunk { string appId; int32 startEventIndex; int32 eventCount; string instanceId; string workflowName; }
  • orchestration.proto
    • new HistoryPropagationScope enum: HISTORY_PROPAGATION_SCOPE_NONE = 0, HISTORY_PROPAGATION_SCOPE_OWN_HISTORY = 1, HISTORY_PROPAGATION_SCOPE_LINEAGE = 2
  • orchestrator_actions.proto
    • ScheduleTaskAction.historyPropagationScope (optional, field 6)
    • CreateChildWorkflowAction.historyPropagationScope (optional, field 6)

What needs to happen here

1. Proto regen + plumbing

  • Pull the updated .proto files from dapr/durabletask-protobuf and regenerate the Python protobuf classes
  • Plumb the new historyPropagationScope field through the schedule-task / create-child-workflow code paths
  • Surface the received PropagatedHistory to the workflow runtime so it can be handed to user code

2. User-facing API to add

Schedule-side (parent workflow author):

  • with_history_propagation(scope) keyword/option on call_activity / call_child_workflow
  • propagate_lineage() and propagate_own_history() helper functions returning a scope value (or expose the enum directly as HistoryPropagationScope.LINEAGE / HistoryPropagationScope.OWN_HISTORY)

Receive-side (child workflow / activity author):

  • get_propagated_history() returning Optional[PropagatedHistory] on both workflow and activity contexts
  • PropagatedHistory dataclass with:
    • events — list of HistoryEvent
    • scope — the scope enum value
    • workflows — chunks (each with app_id, workflow_name, instance_id, start_event_index, event_count)
    • app_ids — deduplicated list of app IDs in the chain
    • convenience filters: get_workflow_by_name(name), get_events_by_app_id(app_id), get_events_by_instance_id(id), get_events_by_workflow_name(name)
    • raises PropagationNotFoundError (or returns None) for missing names

3. Example to add

examples/workflow_history_propagation/ mirroring the Go demo: a 3-tier payment workflow (parent → activity → child workflow with propagate_lineage → activity with propagate_own_history). Standalone dapr run mode at minimum; K8s + signing variant a stretch.

4. Tests

At least one test per scope:

  • Lineage: parent → child receives parent's events
  • OwnHistory: parent → child receives caller's events but NOT grandparent's

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions