Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Web Api - Fire and Forget

I have a Web API's action where I need to run some task and forget about this task. This is how my method is organized now:

public async Task<SomeType> DoSth()
{
    await Task.Run(...);
    .....
    //Do some other work
}

The thing is that obviously it stops at the await line waiting when it's done and only then continues the work. And I need to "fire and forget" Should I just call Task.Run() without any async-await?

like image 476
D. Jones Avatar asked Mar 31 '16 13:03

D. Jones


3 Answers

And I need to "fire and forget"

I have a blog post that goes into details of several different approaches for fire-and-forget on ASP.NET.

In summary: first, try not to do fire-and-forget at all. It's almost always a bad idea. Do you really want to "forget"? As in, not care whether it completes successfully or not? Ignore any errors? Accept occasional "lost work" without any log notifications? Almost always, the answer is no, fire-and-forget is not the appropriate approach.

A reliable solution is to build a proper distributed architecture. That is, construct a message that represents the work to be done and queue that message to a reliable queue (e.g., Azure Queue, MSMQ, etc). Then have an independent backend that process that queue (e.g., Azure WebJob, Win32 service, etc).

Should I just call Task.Run() without any async-await?

No. This is the worst possible solution. If you must do fire-and-forget, and you're not willing to build a distributed architecture, then consider Hangfire. If that doesn't work for you, then at the very least you should register your cowboy background work with the ASP.NET runtime via HostingEnvironment.QueueBackgroundWorkItem or my ASP.NET Background Tasks library. Note that QBWI and AspNetBackgroundTasks are both unreliable solutions; they just minimize the chance that you'll lose work, not prevent it.

like image 197
Stephen Cleary Avatar answered Nov 11 '22 03:11

Stephen Cleary


For fire and forget, use this

Task.Factory.StartNew(async () =>
{
    using (HttpClient client = new HttpClient())
    {
        await client.PostAsync("http://localhost/api/action", new StringContent(""));
    }
});
like image 37
Catalin Avatar answered Nov 11 '22 03:11

Catalin


True fire and forget tasks can be difficult in asp.net as they can often die along with the request that they were created as part of.

If you are using 4.5.2+ then you can use QueueBackgroundWorkItem to run the task. By registering tasks via this method the AppDomain will try to delay shutting down until they have all completed but there can still be instances when they will be killed before they are completed. This is probably the simplest thing to do but worth reading into to see exactly what instances can cause jobs to be cancelled.

HostingEnvironment.QueueBackgroundWorkItem(async cancellationToken =>
{
  await Task.Run(...);
});

There is an tool called hangfire that uses a persistent store to ensure that a task has completed and has built-in retry and error recording functionality. This is more for "background tasks" but does suit fire and forget. This is relatively easy to setup and offers a variety of backing stores, I can't recall the exact details but some require a license and some don't (like MSSQL).

like image 10
Fermin Avatar answered Nov 11 '22 04:11

Fermin