Reputation:
I have 2 background services.
Both of them have a call to a method that is NOT async. This method I cannot control - I can wrap it, sure.
I wire the backgroundservice(s) up by adding them to the servicecollection:
services.AddSingleton<IHostedService, BS1>();
services.AddSingleton<IHostedService, BS2>();
The execute async looks like this in each of them.
protected async override Task ExecuteAsync(CancellationToken stoppingToken)
{
log.LogInformation($"Start consuming from topic: {eventStreamConsumer.Topic}");
while (stoppingToken.IsCancellationRequested == false)
{
try
{
async...
var consumeResult = eventStreamConsumer.Consume();
The Consume method is blocking the thread here since it's not async.
My approach so far has been to wrap the inner workings of execute async into a Task.Factory.Start, but if the Consume does not return, the thread still hangs.
I would like to truly run this on a separate thread, but bear in mind the execute async has dependencies on other instances in the class - don't know if the will be a problem?
How does this approach look like?
protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
var task = new Task(() =>
{
while (stoppingToken.IsCancellationRequested == false)
{
try
{
var consumeResult = eventStreamConsumer.Consume();
....
}
catch (Exception e)
{
//swallow
}
}
}, stoppingToken, TaskCreationOptions.LongRunning);
task.Start();
return Task.FromResult<object>(null);
}
Upvotes: 1
Views: 1482
Reputation: 63772
The way async
works is exactly that it returns a Task
. That's the part you're missing: instead of waiting for the task to finish or reading its Result
, return the task itself.
Also, don't use new Task
followed by Task.Start
. Task.Run
is what you actually want pretty much every time (the only exception being if you're creating your own task scheduler).
Upvotes: 1