Skip to content

Conversation

@avin3sh
Copy link
Contributor

@avin3sh avin3sh commented Jan 28, 2026

This is to make CommandHandlerInvokerMiddleware correctly 'await' the task before accessing its result, similar to how this is done in RequestHandlerInvokerMiddleware.

Without this change, attempting to access result of a cancelled task would result in TargetInvocationException / AggregateException which breaks the task processing in BackgroundCommandSenderHostedService due to unhandled exception, thus breaking the background queue and particularly in bulk dispatch workflow causing remaining workflows to not get dispatched.

There are also Unit Tests included but they may be overkill for this scenario, can remove.

This is to make `CommandHandlerInvokerMiddleware` correctly 'await' the task before accessing its result, similar to how this is done in `RequestHandlerInvokerMiddleware`. Without this change, attempting to access result of a cancelled task would result in TargetInvocationException / AggregateException which breaks the task processing in `BackgroundCommandSenderHostedService` due to unhandled exception, thus breaking the background queue and particularly in bulk dispatch workflow causing remaining workflows to not get dispatched
@avin3sh avin3sh marked this pull request as draft January 28, 2026 18:36
@avin3sh avin3sh marked this pull request as ready for review February 2, 2026 14:59
@avin3sh
Copy link
Contributor Author

avin3sh commented Feb 2, 2026

@dotnet-policy-service agree company="D.E. Shaw & Co., L.P."

Copy link
Member

@sfmskywalker sfmskywalker left a comment

Choose a reason for hiding this comment

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

Perfect 👍🏻

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes exception propagation in the Elsa.Mediator command pipeline so cancellations/faults from command handlers surface as the original exceptions (instead of TargetInvocationException/AggregateException), preventing background command processing from breaking.

Changes:

  • Update CommandHandlerInvokerMiddleware to await the handler task before reading its Result, aligning behavior with the request pipeline.
  • Unwrap TargetInvocationException in handler reflection invocations so callers observe the original exception.
  • Add new unit tests covering successful execution, cancellation, and failure behavior for commands.

Reviewed changes

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

File Description
test/unit/Elsa.Mediator.UnitTests/Elsa.Mediator.UnitTests.csproj Adds a new unit test project for Elsa.Mediator behavior.
test/unit/Elsa.Mediator.UnitTests/CommandCancellationBehaviorTests.cs Adds tests verifying command cancellation and exception propagation behavior.
src/common/Elsa.Mediator/Middleware/Command/Components/CommandHandlerInvokerMiddleware.cs Awaits the invoked task before accessing Result to avoid wrapped exceptions on cancellation/faults.
src/common/Elsa.Mediator/Extensions/HandlerExtensions.cs Unwraps TargetInvocationException for notification/command handler reflection calls.

@sfmskywalker
Copy link
Member

@copilot open a new pull request to apply changes based on the comments in this thread

@sfmskywalker
Copy link
Member

@greptile open a new pull request to apply changes based on the comments in this thread

@greptile-apps
Copy link

greptile-apps bot commented Feb 7, 2026

I cannot create a new pull request on your behalf because:

  1. You own the branch - PR Propagate exceptions from command handlers correctly #7218 is from your fork (avin3sh/elsa-core) on your branch avin3sh-fix-command-handler-invoker-exception-handling
  2. I don't have write access - I can only read from the repository, not create branches or push changes to your fork

To apply the review feedback, you have two options:

Option 1: Update the existing PR (Recommended)
Push additional commits to your branch avin3sh-fix-command-handler-invoker-exception-handling. Here are the changes needed:

1. Fix HandlerExtensions.cs (lines 58 and 79) - Use ExceptionDispatchInfo to preserve stack traces:

using System.Runtime.ExceptionServices;

// At line 58 and 79, replace:
throw ex.InnerException;

// With:
ExceptionDispatchInfo.Capture(ex.InnerException).Throw();

2. Fix CommandCancellationBehaviorTests.cs:

  • Line 56: Change to ThrowsAsync<TaskCanceledException> (matches test name)
  • Line 83: Dispose the service provider/scope (wrap in using)
  • Line 109: Change delay from FromSeconds(10) to FromMilliseconds(500)

Option 2: Ask the PR author
If you're reviewing this PR, ask @avin3sh to apply these changes.

Would you like me to provide the complete corrected code for each file?

@sfmskywalker
Copy link
Member

@avin3sh It looks like Copilot can't implement its suggestions because this is a PR from your fork, so it would be great if you could review the suggestions yourself and resolve them (manually or using your own coding agents, of course). Thanks again!

Use ExceptionDispatchInfo to prevent misleading stacktrace. As well use disposable fixture to actually dispose CommandSender,
@avin3sh avin3sh requested a review from Copilot February 9, 2026 07:59
Copy link
Contributor

Copilot AI left a comment

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 4 out of 4 changed files in this pull request and generated 4 comments.

- Refactor duplicated unwrapping logic into shared InvokeAndUnwrap helper method
- Simplify CommandHandlerInvokerMiddleware to be consistent with
  RequestHandlerInvokerMiddleware (remove redundant await)
- Add Threshold property to test project for consistency
@avin3sh avin3sh requested a review from Copilot February 9, 2026 08:55
Copy link
Contributor

Copilot AI left a comment

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 4 out of 4 changed files in this pull request and generated 4 comments.

- Add ConfigureAwait(false) to await statements in both CommandHandlerInvokerMiddleware and RequestHandlerInvokerMiddleware for consistency and to follow library code best practices
- Increase test timeout from 50ms to 100ms for better CI reliability while still maintaining adequate margin (handler has 500ms delay)
@avin3sh avin3sh requested a review from Copilot February 9, 2026 09:15
Copy link
Contributor

Copilot AI left a comment

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 5 out of 5 changed files in this pull request and generated 4 comments.

@avin3sh
Copy link
Contributor Author

avin3sh commented Feb 9, 2026

@sfmskywalker I have made some more changes as per the Agent's suggestions, I don't think the more recent suggestions are very helpful / are scope-creep.

There was a conflict caused by #7226 where ConfigureAwait(false) was introduced in CommandHandlerMiddleware. I did some cleanup and for sake of cosistency/readability ported the same change to RequestHandlerMiddleware too.

Let me know if you think further changes are necessary.

@sfmskywalker
Copy link
Member

Looks good to me - thanks for the hard work @avin3sh !

@sfmskywalker sfmskywalker merged commit ac62311 into elsa-workflows:main Feb 9, 2026
2 of 3 checks passed
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.

2 participants