Skip to content

Add support for async workflow activities#1053

Open
seherv wants to merge 22 commits into
dapr:mainfrom
seherv:async-compat
Open

Add support for async workflow activities#1053
seherv wants to merge 22 commits into
dapr:mainfrom
seherv:async-compat

Conversation

@seherv

@seherv seherv commented May 25, 2026

Copy link
Copy Markdown
Contributor

Description

Workflow activities can now be async, and the runtime will automatically dispatch them to the event loop. Sync activities are still dispatched to the thread pool. The user-facing API remains exactly the same.

Basic benchmarks

Ran all of these on an M3 Pro (Python 3.13). The async activities take a 100KB array of random data, do asyncio.sleep(1) and return the zeroes unmodified.

1. Fan-out from one workflow

Activities Async
100 1.03 s
1 000 1.24 s
10 000 11.03 s

2. Fan-out from multiple workflows × 3 activities

Workflows × activities Async
100 × 3 1.09 s
1 000 × 3 3.60 s
10 000 × 3 39.51 s

3. Variable payload (100 workflows × 3 activities)

Payload Async
1 KB 3.23 s
100 KB 3.64 s
1 MB 8.80 s

Issue reference

Closes #834, #897 and #975

Checklist

Please make sure you've completed the relevant tasks for this PR, out of the following list:

  • Code compiles correctly
  • Created/updated tests
  • Extended the documentation

f"Activity '{req.name}#{req.taskId}' result is too large to deliver "
f'(RESOURCE_EXHAUSTED). Failing the activity task: {rpc_error.details()}'
)
failure_res = pb.ActivityResponse(

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This nesting got hard to follow, I needed to refactor this file to understand the logic better.

@codecov

codecov Bot commented May 25, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 87.83784% with 63 lines in your changes missing coverage. Please review.
✅ Project coverage is 83.05%. Comparing base (bffb749) to head (b1e0c3f).
⚠️ Report is 142 commits behind head on main.

Files with missing lines Patch % Lines
...-workflow/dapr/ext/workflow/_durabletask/worker.py 54.92% 32 Missing ⚠️
...workflow/tests/test_async_activity_registration.py 92.72% 12 Missing ⚠️
...kflow/dapr/ext/workflow/_durabletask/aio/client.py 50.00% 11 Missing ⚠️
...ext-workflow/dapr/ext/workflow/workflow_runtime.py 93.02% 3 Missing ⚠️
...ests/durabletask/test_async_dispatch_regression.py 93.18% 3 Missing ⚠️
...rkflow/tests/durabletask/test_activity_executor.py 93.33% 1 Missing ⚠️
.../tests/durabletask/test_activity_executor_async.py 97.61% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1053      +/-   ##
==========================================
- Coverage   86.63%   83.05%   -3.58%     
==========================================
  Files          84      151      +67     
  Lines        4473    15289   +10816     
==========================================
+ Hits         3875    12698    +8823     
- Misses        598     2591    +1993     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Signed-off-by: Sergio Herrera <627709+seherv@users.noreply.github.com>
@JoshVanL JoshVanL requested a review from Copilot May 26, 2026 10:45

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@seherv seherv requested a review from Copilot May 27, 2026 07:46

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.

Comment thread ext/dapr-ext-workflow/dapr/ext/workflow/_durabletask/worker.py Outdated
Comment thread ext/dapr-ext-workflow/docs/concurrency.md Outdated
Comment thread ext/dapr-ext-workflow/AGENTS.md Outdated
Comment thread ext/dapr-ext-workflow/AGENTS.md Outdated
Comment thread ext/dapr-ext-workflow/tests/test_async_activity_registration.py
Comment thread ext/dapr-ext-workflow/benchmarks/RESULTS.md Outdated
Signed-off-by: Sergio Herrera <627709+seherv@users.noreply.github.com>
@seherv seherv requested a review from Copilot June 1, 2026 09:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 11 changed files in this pull request and generated 4 comments.

Comments suppressed due to low confidence (1)

ext/dapr-ext-workflow/dapr/ext/workflow/_durabletask/worker.py:678

  • This adds an extra registry lookup (get_activity) and inspect.iscoroutinefunction check on the hot dispatch path, but _ActivityExecutor._resolve() will look up the activity again during execution. Consider plumbing activity_fn (and/or an is_async flag decided at registration time) through to the executor so each activity work item only does one lookup in total.
                                activity_handler,
                                work_item.activityRequest,
                                stub,
                                work_item.completionToken,
                            )

Comment thread ext/dapr-ext-workflow/tests/test_async_activity_registration.py Outdated
Comment thread ext/dapr-ext-workflow/dapr/ext/workflow/_durabletask/worker.py
Comment thread ext/dapr-ext-workflow/docs/concurrency.md Outdated
Comment thread ext/dapr-ext-workflow/benchmarks/bench_async_activities.py Outdated
Signed-off-by: Sergio Herrera <627709+seherv@users.noreply.github.com>
@seherv seherv requested a review from Copilot June 1, 2026 11:43

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 11 changed files in this pull request and generated 5 comments.

Comment thread ext/dapr-ext-workflow/benchmarks/bench_async_activities.py Outdated
Comment thread ext/dapr-ext-workflow/benchmarks/bench_async_activities.py Outdated
Comment thread ext/dapr-ext-workflow/tests/test_async_activity_registration.py Outdated
Comment thread ext/dapr-ext-workflow/dapr/ext/workflow/_durabletask/worker.py
Signed-off-by: Sergio Herrera <627709+seherv@users.noreply.github.com>
@seherv seherv requested a review from Copilot June 1, 2026 13:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 12 changed files in this pull request and generated 4 comments.

Comment thread ext/dapr-ext-workflow/tests/test_async_activity_registration.py Outdated
Comment thread ext/dapr-ext-workflow/dapr/ext/workflow/_durabletask/worker.py
Comment thread ext/dapr-ext-workflow/dapr/ext/workflow/_durabletask/worker.py
Comment thread ext/dapr-ext-workflow/dapr/ext/workflow/_durabletask/worker.py Outdated
seherv added 3 commits June 1, 2026 16:11
Signed-off-by: Sergio Herrera <627709+seherv@users.noreply.github.com>
Signed-off-by: Sergio Herrera <627709+seherv@users.noreply.github.com>
@seherv seherv requested a review from Copilot June 1, 2026 14:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 13 changed files in this pull request and generated 4 comments.

Comment thread ext/dapr-ext-workflow/docs/concurrency.md
Comment thread ext/dapr-ext-workflow/AGENTS.md Outdated
Comment thread ext/dapr-ext-workflow/benchmarks/bench_async_activities.py Outdated
Comment thread ext/dapr-ext-workflow/dapr/ext/workflow/_durabletask/worker.py
Signed-off-by: Sergio Herrera <627709+seherv@users.noreply.github.com>
@seherv seherv requested a review from Copilot June 1, 2026 14:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 15 changed files in this pull request and generated 3 comments.

Comment thread ext/dapr-ext-workflow/dapr/ext/workflow/_durabletask/worker.py
Comment thread ext/dapr-ext-workflow/docs/concurrency.md Outdated
Signed-off-by: Sergio Herrera <627709+seherv@users.noreply.github.com>
@seherv seherv requested a review from Copilot June 2, 2026 09:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 15 changed files in this pull request and generated 7 comments.

Comment thread ext/dapr-ext-workflow/dapr/ext/workflow/workflow_runtime.py
Comment thread ext/dapr-ext-strands/pyproject.toml
Comment thread ext/dapr-ext-workflow/dapr/ext/workflow/_durabletask/worker.py
Comment thread ext/dapr-ext-workflow/dapr/ext/workflow/_durabletask/worker.py
Comment thread ext/dapr-ext-workflow/docs/concurrency.md
Comment thread ext/dapr-ext-workflow/dapr/ext/workflow/_durabletask/worker.py
seherv added 3 commits June 2, 2026 12:51
Signed-off-by: Sergio Herrera <627709+seherv@users.noreply.github.com>
Signed-off-by: Sergio Herrera <627709+seherv@users.noreply.github.com>
@seherv seherv marked this pull request as ready for review June 2, 2026 13:00
@seherv seherv requested review from a team as code owners June 2, 2026 13:00
Signed-off-by: Sergio Herrera <627709+seherv@users.noreply.github.com>
@seherv seherv marked this pull request as draft June 2, 2026 17:26
@seherv

seherv commented Jun 2, 2026

Copy link
Copy Markdown
Contributor Author

Improving benchmarks and regression tests before submitting for review again

seherv added 3 commits June 2, 2026 23:14
Signed-off-by: Sergio Herrera <627709+seherv@users.noreply.github.com>
Signed-off-by: Sergio Herrera <627709+seherv@users.noreply.github.com>
@seherv seherv marked this pull request as ready for review June 2, 2026 21:52
Signed-off-by: Sergio Herrera <627709+seherv@users.noreply.github.com>
@acroca

acroca commented Jun 4, 2026

Copy link
Copy Markdown
Member

Thanks for working on this! I agree with the general direction, async activity support is something we've wanted for a while (#834, #897, #975), and keeping the user-facing API unchanged is the right approach.

I'd like to share my opinion on the benchmarking side, though. I think the sync-vs-async comparison is valuable in the context of this PR, to justify the why behind the change, but not as something we keep and maintain in the codebase. Concretely:

  • The benchmark suite adds ~1,100 lines (benchmarks/, _bench_harness.py), which is more code than the feature itself, and the comparison is essentially a one-off: once async dispatch is merged, it has served its purpose.
  • _bench_harness.py sits inside dapr/ext/workflow/, so it would ship to every user as part of the package.
  • The regression tests in test_async_dispatch_regression.py mostly assert sync-vs-async ratios, which again is the one-off comparison, and they depend on the harness.

My suggestion: run the benchmarks locally and paste the results + methodology into the PR description. Then the harness, the benchmarks/ directory, and the ratio-based tests can be dropped from the PR.

That said, I do think we should keep one simple throughput regression test so the async path can't silently regress, something like running 1000 activities that each take 1 second and asserting the batch completes in well under 10 seconds (ideally it's ~1s, so a 10x bound leaves plenty of headroom for CI noise). That single assertion catches the failure mode we actually care about, async activities accidentally getting serialized, without needing the full harness, and it can be written directly against the runtime in a few dozen lines.

Thoughts?

seherv and others added 3 commits June 9, 2026 13:46
Signed-off-by: Sergio Herrera <627709+seherv@users.noreply.github.com>
Signed-off-by: Sergio Herrera <627709+seherv@users.noreply.github.com>

@sicoyle sicoyle left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

few comments so far. I'm almost half way through the files/changes :)

Comment thread ext/dapr-ext-workflow/benchmarks/_report.py Outdated
Comment thread ext/dapr-ext-workflow/benchmarks/bench_async_activities.py Outdated
Comment thread ext/dapr-ext-workflow/benchmarks/bench_async_activities.py Outdated
Comment thread ext/dapr-ext-workflow/benchmarks/bench_async_activities.py Outdated
Comment thread ext/dapr-ext-workflow/benchmarks/bench_async_activities.py Outdated
Comment thread ext/dapr-ext-workflow/dapr/ext/workflow/_bench_harness.py Outdated
Comment thread ext/dapr-ext-workflow/dapr/ext/workflow/_bench_harness.py Outdated
Comment thread ext/dapr-ext-workflow/dapr/ext/workflow/_bench_harness.py Outdated
Comment thread ext/dapr-ext-workflow/dapr/ext/workflow/_bench_harness.py Outdated
Comment thread ext/dapr-ext-workflow/dapr/ext/workflow/_bench_harness.py Outdated
@seherv

seherv commented Jun 10, 2026

Copy link
Copy Markdown
Contributor Author

Your comments have convinced me that the repo is not the right place for benchmark code. It was very useful to validate everything myself, but I think our users only need to see a summary of the results and their applications are the real stress tests anyway.

I'll remove the bench code and simplify the regression tests to validate only the async side of things.

@seherv seherv marked this pull request as draft June 10, 2026 14:38
Signed-off-by: Sergio Herrera <627709+seherv@users.noreply.github.com>
@seherv seherv marked this pull request as ready for review June 10, 2026 15:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: asyncio support for workflow sdk

4 participants