Magnus
Magnus

Reputation: 73

Best way to handle sync code within an async method

I am implementing a message dispatcher/handler where each handler must implement an interface like Task<Result> HandleAsync(IEvent myevent)

For example:

public async Task<Result> HandleAsync(CustomerChangedEvent ev)
{
    await DoSomethingAsync();
    ...
    return myResult;
}

But sometimes I need to run something which is sync only so no await and that as you know will give you a compiler warning. What I have done is to add await Task.CompletedTask; in my code. Works fine AFAIK but is there any downside doing this?

Another alternative is to drop the async but in that case I need to return a Task, right? For example to return Task.FromResult(myResult).

Is there any benefits for one method over another (or different approach), especially from a performance perspective (like is there any substantial cost to declare a method as async. Personally, I prefer the first alternative. For some reason I find return Task.FromResult harder to read and understand even if the first method adds a dummy command.

EDIT:

Sometimes it is maybe better to rethink the logic. "funatparties" commented why run sync code with an async method.

Reason is that I am implementing an outbox message handler where I am processing a queue with different messages to be processed and some have async operations other not. For each type of message I create a handler class which implements an interface.

I want adding handle a new message type I want it to be as few steps as possible. So basically what you do is to create a new handler which implements a specific interface and register the handler with my dispatcher class (which I probably can do automatically as well using Reflection).

The interface require you to implement Task. When reading the queue it will run the HandleAsync method using the registered handler (depending on message type).

A better approach maybe is that the handler can define either an sync or an async method depending on what I need to do.

Upvotes: 0

Views: 269

Answers (2)

Stephen Cleary
Stephen Cleary

Reputation: 457302

Actually, I recommend ignoring the compiler warning in this case. Most of the time this compiler warning is useful, so I don't recommend disabling it solution-wide, just here.

The problem with Task.FromResult is that you also have to handle exceptions - catch them and return Task.FromException (or Task.FromCanceled). The problem with await Task.CompletedTask is that it's an unnecessarily expensive NOOP.

So I recommend ignoring the compiler warning. If you have to do this in several places, you can write a simple helper type like this.

Upvotes: 2

Gabriel Luci
Gabriel Luci

Reputation: 41008

I'm guessing the compiler warning you are getting is that you're not using await in an async method.

Using await Task.CompletedTask does nothing useful other than suppress the warning. The await keyword does nothing when it acts on a completed Task. You get no benefit, but there is still the overhead of managing an async method and all the background stuff that has to happen to accommodate it.

If you have to return a Task<Result>, but are not doing anything asynchronously, then drop the async and return Task.FromResult(myResult).

Upvotes: 0

Related Questions