This may have been answered somewhere on the web but I've looked at lots of the examples and I still can't figure it out.
I have a sync based service layer boundary (e.g. "ProcessOrder" method). Within this method it performs various functions, a couple of which have async overloads and it makes sense to use these as they wrap I/O bound functions.
However, my confusion is two-fold. From what I've read:
So, with example code such as below (NB: _publisher is wrapper for Azure QueueClient that has Async Send methods):
public void ProcessOrder()
{
// other stuff...
_publisher.PublishAsync(new ItemOrderedEvent()
{
MessageId = Guid.NewGuid(),
IsDurable = true,
}).Wait();
}
Doesn't seem to fit the "async all the way down" rule, and there are warnings about deadlocks etc. on the web due to thread pool exhaustion at high loads about this pattern, but code such as:
public async void ProcessOrder()
{
// other stuff...
await _publisher.PublishAsync(new ItemOrderedEvent()
{
MessageId = Guid.NewGuid(),
IsDurable = true,
});
}
Breaks the "async marked methods should not return void" rule and will not handle exceptions as, from my understanding, there is no Task context to bubble them back from the async method. NB: This is a service boundary - the calling code may be UI, in response to an MSMQ message, a web service call etc. so I do not want "implementation" of the service call to leak higher up. In the current context, IMO, it makes sense for this to be a sync call only.
The publisher method is defined as:
public async Task PublishAsync(IMessageBusMessage message)
{
// do azure stuff
var _queue = QueueClient.CreateFromConnectionString(connectionString, "ItemOrdered");
await _queue.SendAsync(message);
}
So my question is... how the heck do you make use of legitimate I/O bound async methods within a sync based architecture? The typical answer seems to be "you can't" (as suggested by this Calling async methods from a synchronous context) but then I must be missing something as it seems perfectly reasonable to want to offload I/O bound work and let the current thread do some other work, in contexts that are not UI based.
it seems perfectly reasonable to want to offload I/O bound work and let the current thread do some other work, in contexts that are not UI based.
If this is a non-UI thread, and you do have some other work to do while your IO-bound operation is pending, then nothing prevents your from doing so inside your synchronous method:
public void ProcessOrder()
{
// other stuff...
// initiate the IO-bound operation
var task = _publisher.PublishAsync(new ItemOrderedEvent() {});
{
MessageId = Guid.NewGuid(),
IsDurable = true,
}); // do not call .Wait() here
// do your work
for (var i = i; i < 100; i++)
DoWorkItem(i);
// work is done, wait for the result of the IO-bound operation
task.Wait();
}
This might make sense if you cannot afford re-factoring all of your code to use "async all the way down" philosophy (which may be time-consuming, but almost always possible).