Web Api - Fire and Forget - c#

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?

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.

For fire and forget, use this
Task.Factory.StartNew(async () =>
{
using (HttpClient client = new HttpClient())
{
await client.PostAsync("http://localhost/api/action", new StringContent(""));
}
});

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).

I use HangFire.
This is best for me.
An easy way to perform background processing in .NET and .NET Core applications. No Windows Service or separate process required.
Backed by persistent storage. Open and free for commercial use.

I agree with others that you should not just forget about your call. However, to answer your question, if you remove await from the Task.Run() line, the call will not be blocking as shown here
public async Task<SomeType> DoSth()
{
Task.Run(...);
.....
//Do some other work while Task.Run() continues in parallel.
}

For invoking a fire and forget WebApi method, I used the following code to ensure that it returns an OK response. I my case, the bearer authorization token created at login is stored in a cookie:
...
FireAndForget().Wait();
...
private async Task FireAndForget()
{
using (var httpClient = new HttpClient())
{
HttpCookie cookie = this.Request.Cookies["AuthCookieName"];
var authToken = cookie["AuthTokenPropertyName"] as string;
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authToken);
using (var response = await httpClient.GetAsync("http://localhost/api/FireAndForgetApiMethodName"))
{
//will throw an exception if not successful
response.EnsureSuccessStatusCode();
}
}
}

Never fire and forget, because then you won't get to see any errors, which makes for some very awkward troubleshooting if something goes wrong (having the task method do its own exception handling isn't guaranteed to work, because the task may not successfully start in the first place). Unless you really don't mind if the task does anything or not, but that's quite unusual (since, if you truly didn't care, why run the task in the first place)? At the very least, create your task with a continuation:
Task.Run(...)
.ContinueWith(t =>
logException(t.Exception.GetBaseException()),
TaskContinuationOptions.OnlyOnFaulted
)
;
You can make this more sophisticated as your needs dictate.
In the specific case of a web API, you may actually want to wait for your background tasks to finish before you complete your request. If you don't, you're leaving stuff running in the background that may misrepresent how much load your service can really take, or even stop working altogether if clients fire too many requests and you don't do anything to throttle them. You can gather tasks up and issue an await Task.WhenAll(...) at the end to achieve that; this way, you can continue to do useful work while your background tasks plod away, but you don't return until everything's done.

Related

If I'm going to use the result from await immediately, do I get any benefit from async?

Consider the code in this example:
https://learn.microsoft.com/en-us/aspnet/web-api/overview/advanced/calling-a-web-api-from-a-net-client
In several places they have code that looks like this:
if (response.IsSuccessStatusCode)
{
product = await response.Content.ReadAsAsync<Product>();
}
return product;
The way I see it, if there is no independent code following the await, then there is little benefit to using async. (I know that there are many API's that are *AsAsync() only, so in those cases I don't have a choice.)
Or am I missing something? Is there a benefit for going all async, all the time?
Yes there is benefit as we are not blocking caller on the operation that we are doing which is not the case for sync calls.
Think of it was called in windows form application as synchrounous call then on a button click suppose, then the app would be unresponsive and user wouldn't be able to do any operation until the call to Web API method complete s either with success or failure which we don't want nowadays in many cases I.e keep the application responsive for better UX.
The basic purpose is to simplify the old way of using background worker class to do long running operations or I/O bound operations. The asynchronous execution will cause not to block the caller code and resume from where it left when the result is returned back from the operation.
So in the above case calling a Web API method involves network latency and it could take more than normal time and if we are not calling it asynchronously we have blocked the calling code or thread until the result is returned.
Update:
To clarify Calling async method without await wouldnt block but your control would flow through and you won't be able to access the result while await would keep that context, without await you will have to wait for it to complete and block it like Async().Result which ofcoruse means calling async method synchronously.
Hope it helps

Wrapping a non async-method (which does web calls) into async

I know you should only use async for stuff which is not "CPU-intensive", e.g. file writes, web calls etc. and therefore I also know it doesn't makes sense to wrap every method into Task.Run or something similar.
However what should I do when I know a method does a web call, but it doesn't offer an async interface. Is it in this case worth to wrap it?
Concrete example:
I'm using CSOM (Client SharePoint Object Model) in my WebApi application (server) and want to get a SharePoint list.
This is normally done like this:
[HttpGet]
[Route("foo/{webUrl}")]
public int GetNumberOfLists(string webUrl)
{
using (ClientContext context = new ClientContext(webUrl))
{
Web web = context.Web;
context.Load(web.Lists);
context.ExecuteQuery();
return web.Lists.Count;
}
}
And I thought about changing it to something like this:
[HttpGet]
[Route("foo/{webUrl}")]
public async Task<int> GetNumberOfLists(string webUrl)
{
using (ClientContext context = new ClientContext(webUrl))
{
Web web = context.Web;
context.Load(web.Lists);
await Task.Run(() => clientContext.ExecuteQuery());
return web.Lists.Count;
}
}
Does it make sense and does it help? As I understand it, I just create / need a new thread for executing the query ("overhead") but at least the request thread will be free / ready for another request (that would be good).
But is it worth it and should it be done like this?
If so:
Isn't it strange that Microsoft doesn't offer the "async" method out of the box or did they just not care about it?
edit:
updated to use Task.Run as suggested in comment.
However what should I do when I know a method does a web call, but it doesn't offer an async interface.
Unfortunately still somewhat common. As different libraries update their APIs, they will eventually catch up.
Is it in this case worth to wrap it?
Yes, if you're dealing with a UI thread. Otherwise, no.
Concrete example... in my WebApi application (server)
Then, no, you don't want to wrap in Task.Run. As noted in my article on async ASP.NET:
You can kick off some background work by awaiting Task.Run, but there’s no point in doing so. In fact, that will actually hurt your scalability by interfering with the ASP.NET thread pool heuristics... As a general rule, don’t queue work to the thread pool on ASP.NET.
Wrapping with Task.Run on ASP.NET:
Interferes with the ASP.NET thread pool heuristics twice (by taking a thread now and then releasing it later).
Adds overhead (code has to switch threads).
Does not free up a thread (the total number of threads used for this request is almost equal to just calling the synchronous version).
As I understand it, I just create / need a new thread for executing the query ("overhead") but at least the request thread will be free / ready for another request (that would be good).
Yes, but all you're doing is jumping threads, for no benefit. The thread used to block on the query result is one less thread ASP.NET has to use to handle requests, so freeing up one thread by consuming another isn't a good tradeoff.
Isn't it strange that Microsoft doesn't offer the "async" method out of the box or did they just not care about it?
Some of the "older" MS APIs just haven't gotten around to adding async versions yet. They certainly should, but developer time is a finite resource.
This is my personal view of your problem and for me the above way is not required. When we host your API in IIS, the server assigns one thread from thread pool it has in the server. The IIS also has a setting of maxConcurrentRequestsPerCPU maxConcurrentThreadsPerCPU. You can setup these values to serve the request instead of handling the request all by yourself.

Web API Sync Calls Best Practice

Probably this question has already been made, but I never found a definitive answer. Let's say that I have a Web API 2.0 Application hosted on IIS. I think I understand that best practice (to prevent deadlocks on client) is always use async methods from the GUI event to the HttpClient calls. And this is good and it works. But what is the best practice in case I had client application that does not have a GUI (e.g. Window Service, Console Application) but only synchronous methods from which to make the call? In this case, I use the following logic:
void MySyncMethodOnMyWindowServiceApp()
{
list = GetDataAsync().Result().ToObject<List<MyClass>>();
}
async Task<Jarray> GetDataAsync()
{
list = await Client.GetAsync(<...>).ConfigureAwait(false);
return await response.Content.ReadAsAsync<JArray>().ConfigureAwait(false);
}
But unfortunately this can still cause deadlocks on client that occur at random times on random machines.
The client app stops at this point and never returns:
list = await Client.GetAsync(<...>).ConfigureAwait(false);
If it's something that can be run in the background and isn't forced to be synchronous, try wrapping the code (that calls the async method) in a Task.Run(). I'm not sure that'll solve a "deadlock" problem (if it's something out of sync, that's another issue), but if you want to benefit from async/await, if you don't have async all the way down, I'm not sure there's a benefit unless you run it in a background thread. I had a case where adding Task.Run() in a few places (in my case, from an MVC controller which I changed to be async) and calling async methods not only improved performance slightly, but it improved reliability (not sure that it was a "deadlock" but seemed like something similar) under heavier load.
You will find that using Task.Run() is regarded by some as a bad way to do it, but I really couldn't see a better way to do it in my situation, and it really did seem to be an improvement. Perhaps this is one of those things where there's the ideal way to do it vs. the way to make it work in the imperfect situation that you're in. :-)
[Updated due to requests for code]
So, as someone else posted, you should do "async all the way down". In my case, my data wasn't async, but my UI was. So, I went async down as far as I could, then I wrapped my data calls with Task.Run in such as way that it made sense. That's the trick, I think, to figure out if it makes sense that things can run in parallel, otherwise, you're just being synchronous (if you use async and immediately resolve it, forcing it to wait for the answer). I had a number of reads that I could perform in parallel.
In the above example, I think you have to async up as far as makes sense, and then at some point, determine where you can spin off a t hread and perform the operation independent of the other code. Let's say you have an operation that saves data, but you don't really need to wait for a response -- you're saving it and you're done. The only thing you might have to watch out for is not to close the program without waiting for that thread/task to finish. Where it makes sense in your code is up to you.
Syntax is pretty easy. I took existing code, changed the controller to an async returning a Task of my class that was formerly being returned.
var myTask = Task.Run(() =>
{
//...some code that can run independently.... In my case, loading data
});
// ...other code that can run at the same time as the above....
await Task.WhenAll(myTask, otherTask);
//..or...
await myTask;
//At this point, the result is available from the task
myDataValue = myTask.Result;
See MSDN for probably better examples:
https://msdn.microsoft.com/en-us/library/hh195051(v=vs.110).aspx
[Update 2, more relevant for the original question]
Let's say that your data read is an async method.
private async Task<MyClass> Read()
You can call it, save the task, and await on it when ready:
var runTask = Read();
//... do other code that can run in parallel
await runTask;
So, for this purpose, calling async code, which is what the original poster is requesting, I don't think you need Task.Run(), although I don't think you can use "await" unless you're an async method -- you'll need an alternate syntax for Wait.
The trick is that without having some code to run in parallel, there's little point in it, so thinking about multi-threading is still the point.
Using Task<T>.Result is the equivalent of Wait which will perform a synchronous block on the thread. Having async methods on the WebApi and then having all the callers synchronously blocking them effectively makes the WebApi method synchronous. Under load you will deadlock if the number of simultaneous Waits exceeds the server/app thread pool.
So remember the rule of thumb "async all the way down". You want the long running task (getting a collection of List) to be async. If the calling method must be sync you want to make that conversion from async to sync (using either Result or Wait) as close to the "ground" as possible. Keep they long running process async and have the sync portion as short as possible. That will greatly reduce the length of time that threads are blocked.
So for example you can do something like this.
void MySyncMethodOnMyWindowServiceApp()
{
List<MyClass> myClasses = GetMyClassCollectionAsync().Result;
}
Task<List<MyClass>> GetMyListCollectionAsync()
{
var data = await GetDataAsync(); // <- long running call to remote WebApi?
return data.ToObject<List<MyClass>>();
}
The key part is the long running task remains async and not blocked because await is used.
Also don't confuse the responsiveness with scalability. Both are valid reasons for async. Yes responsiveness is a reason for using async (to avoid blocking on the UI thread). You are correct this wouldn't apply to a back end service however this isn't why async is used on a WebApi. The WebApi is also a non GUI back end process. If the only advantage of async code was responsiveness of the UI layer then WebApi would be sync code from start to finish. The other reason for using async is scalability (avoiding deadlocks) and this is the reason why WebApi calls are plumbed async. Keeping the long running processes async helps IIS make more efficient use of a limited number of threads. By default there are only 12 worker threads per core. This can be raised but that isn't a magic bullet either as threads are relatively expensive (about 1MB overhead per thread). await allows you to do more with less. More concurrent long running processes on less threads before a deadlock occurs.
The problem you are having with deadlocks must stem from something else. Your use of ConfigureAwait(false) prevents deadlocks here. Solve the bug and you are fine.
See Should we switch to use async I/O by default? to which the answer is "no". You should decide on a case by case basis and choose async when the benefits outweigh the costs. It is important to understand that async IO has a productivity cost associated with it. In non-GUI scenarios only a few targeted scenarios derive any benefit at all from async IO. The benefits can be enormous, though, but only in those cases.
Here's another helpful post: https://stackoverflow.com/a/25087273/122718

Asynchronous DB-Query to trigger Stored Procedure

I want to performa an asynchronous DB Query in C# that calls a stored procedure for a Backup. Since we use Azure this takes about 2 minutes and we don't want the user to wait that long.
So the idea is to make it asynchronous, so that the task continues to run, after the request.
[HttpPost]
public ActionResult Create(Snapshot snapshot)
{
db.Database.CommandTimeout = 7200;
Task.Run(() => db.Database.ExecuteSqlCommandAsync("EXEC PerformSnapshot #User = '" + CurrentUser.AccountName + "', #Comment = '" + snapshot.Comment + "';"));
this.ShowUserMessage("Your snapshot has been created.");
return this.RedirectToActionImpl("Index", "Snapshots", new System.Web.Routing.RouteValueDictionary());
}
I'm afraid that I haven't understood the concept of asynchronous taks. The query will not be executed (or aborted?), if I don't use the wait statement. But actually "waiting" is the one thing I espacially don't want to do here.
So... why am I forced to use wait here?
Or will the method be started, but killed if the requst is finished?
We don't want the user to wait that long.
async-await won't help you with that. Odd as it may sound, the basic async-await pattern is about implementing synchronous behavior in a non-blocking fashion. It doesn't re-arrange your logical flow; in fact, it goes to great lengths to preserve it. The only thing you've changed by going async here is that you're no longer tying up a thread during that 2-minute database operation, which is a huge win your app's scalability if you have lots of concurrent users, but doesn't speed up an individual request one bit.
I think what you really want is to run the operation as a background job so you can respond to the user immediately. But be careful - there are bad ways to do that in ASP.NET (i.e. Task.Run) and there are good ways.
Dave, you're not forced to use await here. And you're right - from user perspective it still will take 2 minutes. The only difference is that the thread which processes your request can now process other requests meanwhile database does its job. And when database finishes, the thread will continue process your request.
Say you have limited number of threads capable to process HTTP request. This async code will help you to process more requests per time period, but it won't help user to get the job done faster.
This seems to be down to a misunderstanding as to what async and await do.
async does not mean run this on a new thread, in essence it acts as a signal to the compiler to build a state machine, so a method like this:
Task<int> GetMeAnInt()
{
return await myWebService.GetMeAnInt();
}
sort of (cannot stress this enough), gets turned into this:
Task<int> GetMeAnInt()
{
var awaiter = myWebService.GetMeAnInt().GetAwaiter();
awaiter.OnCompletion(() => goto done);
return Task.InProgress;
done:
return awaiter.Result;
}
MSDN has way more information about this, and there's even some code out there explaining how to build your own awaiters.
async and await at their very core just enable you to write code that uses callbacks under the hood, but in a nice way that tells the compiler to do the heavy lifting for you.
If you really want to run something in the background, then you need to use Task:
Task<int> GetMeAnInt()
{
return Task.Run(() => myWebService.GetMeAnInt());
}
OR
Task<int> GetMeAnInt()
{
return Task.Run(async () => await myWebService.GetMeAnInt());
}
The second example uses async and await in the lambda because in this scenario GetMeAnInt on the web service also happens to return Task<int>.
To recap:
async and await just instruct the compiler to do some jiggerypokery
This uses labels and callbacks with goto
Fun fact, this is valid IL but the C# compiler doesn't allow it for your own code, hence why the compiler can get away with the magic but you can't.
async does not mean "run on a background thread"
Task.Run() can be used to queue a threadpool thread to run an arbitrary function
Task.Factory.Start() can be used to grab a brand new thread to run an arbitrary function
await instructs the compiler that this is the point at which the result of the awaiter for the awaitable (e.g. Task) being awaited is required - this is how it knows how to structure the state machine.
As I describe in my MSDN article on async ASP.NET, async is not a silver bullet; it doesn't change the HTTP protocol:
When some developers learn about async and await, they believe it’s a way for the server code to “yield” to the client (for example, the browser). However, async and await on ASP.NET only “yield” to the ASP.NET runtime; the HTTP protocol remains unchanged, and you still have only one response per request.
In your case, you're trying to use a web request to kick off a backend operation and then return to the browser. ASP.NET was not designed to execute backend operations like this; it is only a web tier framework. Having ASP.NET execute work is dangerous because ASP.NET is only aware of work coming in from its requests.
I have an overview of various solutions on my blog. Note that using a plain Task.Run, Task.Factory.StartNew, or ThreadPool.QueueUserWorkItem is extremely dangerous because ASP.NET doesn't know anything about that work. At the very least you should use HostingEnvironment.QueueBackgroundWorkItem so ASP.NET at least knows about the work. But that doesn't guarantee that the work will actually ever complete.
A proper solution is to place the work in a persistent queue and have an independent background worker process that queue. See the Asynchronous Messaging Primer (specifically, your scenario is "Decoupling workloads").

MVC4 + async/await + return response before action completes

In my MVC4 app I need to add a controller for uploading and processing large files. Immediately after the file is uploaded I need to start async processing of that file and return response to the browser without waiting for the processing to complete.
Obviously I could start a new thread for processing the file manually, but I'm wondering if I can implement this scenario using async/await mechanism introduced with .net 4.5
To test the concept I've tried something like this:
public async Task<ActionResult> Test()
{
TestAsync();
return View("Test");
}
public async void TestAsync()
{
await LongRunning();
}
private Task<int> LongRunning()
{
return Task<int>.Factory.StartNew(() => Pause());
}
private int Pause()
{
Thread.Sleep(10000);
return 3;
}
The async mechanism seems to work in general: when I debug the code I hit the "return View("Test");" line before the line "return 3". However, the browser receives the response only after the Pause method completes.
This seems to behave like regular async controllers (the ones with Async and Completed methods). Is there a way to use async/await in controllers for my scenario?
Obviously I could start a new thread for processing the file manually, but I'm wondering if I can implement this scenario using async/await mechanism introduced with .net 4.5
No, you cannot, because async doesn't change the HTTP protocol.
Svick and James have already posted the correct answers as comments, which I duplicate below for convenience:
IIS can recycle your application pretty much at any time.
If you have long-running things to do async to the request, do them elsewhere. The 'typical' is a persistent queue (MSMQ, Azure, RabbitMQ, etc) with something else (windows service, exe run by task scheduler, app using Quartz.net, etc) processing them.
To summarize, HTTP gives you one request and one response (async - and anything else - won't change this).
ASP.NET is designed around HTTP requests (and makes assumptions like "if there are no outstanding requests, then it's safe to stop this web site"). You can kick off a new thread and keep your upload in memory (which is the easiest way to do it), but it's strongly not recommended.
For your situation, I recommend you follow James' suggestion:
When your upload completes, save the upload to persistent storage (e.g., an Azure queue), and return a "ticket" to the browser.
Have some other process (e.g., an Azure worker role) process the queue, eventually marking it as complete.
Have the browser poll the server with its "ticket". The server uses the "ticket" to look up the file in persistent storage and return whether or not it's complete.
There are some variations to this (e.g., using SignalR to notify the browser when processing is complete), but the general architecture is the same.
This is complex, but it's the right way to do it.
You have an error in your code.
You must await the call to TestAsync in your action.
If you don't, it simply returns a "Task" object without running anything.
public async Task<ActionResult> Test()
{
await TestAsync();
return View("Test");
}
and the correct way to sleep in an async method is to call
await Task.Delay(10000);
You have to change the signature of TestAsync: you should not mark a method async if it returns void. It must return Task instead. Returning void is reserved for compatibility with .net events.
public async Task TestAsync()
{
await LongRunning();
}
The method body is the same.
Your LongRunning method is synchronously sleeping 10 seconds. Change it so the sleep happens in the task instead.

Categories