We're running an ASP.NET WebAPI 2 service and we want to log some requests with our logger to email/database.
Because it's background work, and because in asp.net I figured we should use HostingEnvironment.QueueBackgroundWorkItem to run it in the background.
I want my logs to all be in order - to my surprise I could not find anything indicating that QueueBackgroundWorkItem actually guarantees that the queued work items run in order or indicates it doesn't.
So, my question is: Does QueueBackgroundWorkItem guarantee that work queued gets executed in order?
HostingEnvironment.QueueBackgroundWorkItem((e) => Console.WriteLine("A"));
HostingEnvironment.QueueBackgroundWorkItem((e) => Console.WriteLine("B"));
Do I know that the output of the above snippet is always:
A
B
Or can it be out of order?
There appears to be nothing contractual in the documentation.
Looking at the reference source, it appears to use a class called BackgroundWorker to actually execute these tasks.
In turn, this appears to be running the tasks on the ThreadPool and explicitly may be executing multiple tasks in parallel:
public void ScheduleWorkItem(Func<CancellationToken, Task> workItem) {
Debug.Assert(workItem != null);
if (_cancellationTokenHelper.IsCancellationRequested) {
return; // we're not going to run this work item
}
// Unsafe* since we want to get rid of Principal and other constructs specific to the current ExecutionContext
ThreadPool.UnsafeQueueUserWorkItem(state => {
lock (this) {
if (_cancellationTokenHelper.IsCancellationRequested) {
return; // we're not going to run this work item
}
else {
_numExecutingWorkItems++;
}
}
RunWorkItemImpl((Func<CancellationToken, Task>)state);
}, workItem);
}
So I'd say it's unsafe to assume anything about what order two queued tasks will complete in.
QueueBackgroundWorkItem guarantee that work queued gets executed in order
Reference from HostingEnvironment.QueueBackgroundWorkItem
New HostingEnvironment.QueueBackgroundWorkItem method that lets you schedule small background work items. ASP.NET tracks these items and prevents IIS from abruptly terminating the worker process until all background work items have completed. These will enable ASP.NET applications to reliably schedule Async work items.
Related
I have the following action in my controller:
[HttpPost("run")]
public Task<object> Run([FromBody] ResearchRequest researchRequest)
{
researchService.RunAsync(researchRequest);
return new{ queued = true };
}
The controller needs to handle a task that takes several minutes.
Is this the correct way to release researchService.RunAsync to handle its job?
Or is there a better approach.
Thanks
If you are wanting to check that a process is already running, you could mark it as in progress somewhere on the server side (in a task in the database or such) and then when displaying the UI call a method on the server to check the state of your in progress flag.
that way the UI could navigate away from that page and return to still see that the process had been started
You can do that if RunAsync is making I/O requests, but you wouldn't return a Task:
[HttpPost("run")]
public object Run([FromBody] ResearchRequest researchRequest)
{
researchService.RunAsync(researchRequest);
return new{ queued = true };
}
That will start running RunAsync on the same thread, just like any other method. At the first await in RunAsync that acts on an incomplete Task, RunAsync will return its own incomplete Task, at which point control returns back to your Run action and your object is returned. You won't be waiting for whatever I/O operation RunAsync makes.
If RunAsync is taking a long time because of CPU calculations (not I/O), then that won't do anything for you because, remember, it starts running on the same thread. You will have to start it on another thread, which you can do using Task.Run:
[HttpPost("run")]
public Task<object> Run([FromBody] ResearchRequest researchRequest)
{
Task.Run(() => researchService.RunAsync(researchRequest));
return new{ queued = true };
}
But!
In both cases, ASP.NET will have no idea that RunAsync is running in the background. If the IIS app pool is shut down or recycled for any reason, that job will be killed part way through. Note that by default, IIS is configured to shut down an app pool after 20 minutes of no HTTP requests coming in.
If that is unacceptable to you, then you're better off writing the job to a queue in a database or something and doing that background processing in a Windows service.
I'm new to background work (and generally in Task usage) and have a doubts about my implementation.
(Note: If you think it's too long, let me know by comment and I'll shorten it)
Assume a WCF service which returns currencys rates:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Single)]
public class RatesServiceSvc : IGetRatesService
The RatesServiceSvc depends on IRatesService(singelton).
IRatesService depens on IRatesQueueDispatcher.
holds ratesCache dictionary. and in its constructor calls to RunDispatcher(_ratesQueue, _dispatcherCancellationTokenSource);
The internal implementation of the IRatesService is like this: The service instantiate a third party queue which gets from the network the current rates and pushes them as events to the queue (endlessly). In order to fetch the events I need to invoke the IRatesQueueDispatcher.Run(...) that runs backgroun loop:
The IRatesService implementation:
private void RunDispatcher(Queue queue, CancellationTokenSource dispatcherCancellationTokenSource)
{
Task<TaskCompletionCause> dispatcher = Task.Run(() => _queueDispatcher.Run(queue, dispatcherCancellationTokenSource.Token));
dispatcher.ContinueWith((dispatcherTask) =>
{
HandleRunningTaskTermination(dispatcherTask.Result);
});
}
IRatesQueueDispatcher.Run() Imlementation:
while (!cancellationToken.IsCancellationRequested && IsRatesQueueOk(eventsCount))
{
eventsCount = ratesQueueToDispatch.Dispatch();
if (eventsCount < 0)
{
Thread.Sleep(_sleepTimeWhenReutersQueueEmpty);
}
}
The queue.Dispach() call, leads to invoke (in the same thread) to the implementation of EventClient.ProcessEvent(event) (which registered in the initialization phase). The data fetched from the events inserted to the rateCache (in this case it's a ConcurrentDictionary)
The application needs:
The background loop will run endlessly.
If background loop fails for some reason I need to know it immediately.
If application has another issue I need to kill the background task.
The question:
Do my solution of running the backgroun work by Task.Run(...).ContinueWith(...) is Ok? I read in some palces about "Fire and Forget" Dangers (here
and here) also I know .NET 4.5.2 suggests the HostingEnvironment.QueueBackgroundWorkItem
but I'm not sure if it's the appropriate solution for me. Because:
I need to know if the worker failed from its internal reason.
It seems to me that the main purpose of the HostingEnvironment.QueueBackgroundWorkItem is to promise the finish of the running task before application_end. For my needs There isn't meaning of running the background work when application ends, and also vice versa - If background failed there is no meaning of the application to run without it. For that reason I implemented the HandleRunningTaskTermination() to recycle the application by invoke System.Web.HttpRuntime.UnloadAppDomain();.
After all, I'm worried about my implemetation and I'm looking for a better solution. There is better??
Always managing to confuse myself working with async, I'm after a bit of validation/confirmation here that i'm doing what i think i'm doing in the following scenarios..
given the following trivial example:
// pretend / assume these are json msgs or something ;)
var strEvents = new List<string> { "event1", "event2", "event3" };
i can post each event to an eventhub simply as follows:
foreach (var e in strEvents)
{
// Do some things
outEventHub.Add(e); // ICollector
}
the foreach will run on a single thread, and execute each thing inside sequentially.. the posting to eventhub will also remain on the same thread too i guess??
Changing ICollector to IAsyncCollector, and achieve the following:
foreach (var e in strEvents)
{
// Do some things
await outEventHub.AddAsync(e);
}
I think i am right here in saying that the foreach will run on a single thread, the actual sending to the event hub will be pushed off elsewhere? Or at least not block that same thread..
Changing to Parallel.ForEach event as these events will be arriving 100+ or so at a time:
Parallel.ForEach(events, async (e) =>
{
// Do some things
await outEventHub.AddAsync(e);
});
Starting to get a bit hazy now, as i am not sure what really is going on now... afaik the each event has it's own thread (within the bounds of the hardware) and steps within that thread do not block it.. so this trivial example aside.
Finally, i could turn them all in to Tasks i thought..
private static async Task DoThingAsync(string e, IAsyncCollector<string> outEventHub)
{
await outEventHub.AddAsync(e);
}
var t = new List<Task>();
foreach (var e in strEvents)
{
t.Add(DoThingAsync(e, outEventHub));
}
await Task.WhenAll(t);
now i am really hazy, and i think this is prepping everything on a single thread.. and then running everything exactly at the same time, on any thread available??
I appreciate that in order to determine which is right for the job at hand benchmarking is required... but an explanation of what the framework is doing in each situation would be super helpful for me right now..
Parallel != async
This is the main idea here. Both of them have their uses, and they can be used together, but they are very different. You are mostly right with your assumptions, but let me clarify:
Simple foreach
This is non-parallel and non-async. Nothing to talk about.
Await inside foreach
This is async code that is non-parallel.
foreach (var e in strEvents)
{
// Do some things
await outEventHub.AddAsync(e);
}
This will all take place on a single thread. It takes an event, starts adding it to your event hub, and while it is being completed (I'm guessing it does some sort of network IO) it hands back the thread to the thread pool (or UI if it was called on a UI thread) so it can do other work while wating on AddAsync to return. But as you said, is is not parallel at all.
Parallel Foreach (async)
This one is a trap! In short, Parallel.Foreach is designed for synchronous workloads. We'll get back to this but first let's assume you used it with the non-async code.
Parallel foreach (sync)
A.k.a. Parallel but not async.
Parallel.ForEach(events, (e) =>
{
// Do some things
outEventHub.Add(e);
});
Each item will get its own "Task", but they won't spawn a thread. Creating threads is expensive, and in an optimal case there is no point in having more threads than CPU cores. Instead these tasks run on a ThreadPool, which has just as many Threads as optimal. Each thread takes a task, works on it, then takes another one, etc.
You can think of it as - on a 4 core machine - having 4 workers around a pile of tasks, so 4 of them are being run at a time. You can imagine that this is not ideal in case of IO bound workloads (which this most likely is). If your network is slow, you can have all 4 threads blocked on trying to send the event out, while they could be doing useful work. This leads us to...
Tasks
Async and potentially parallel (depends on the usage).
Your description is correct here, too, except for the ThreadPool, it is kikking off all the tasks at once (on the main thread), which then run on the pool's threads. While they are running, the main thread is released, which then can do other work, as needed. Up to this point it is the same as the Parallel.Foreach case. But:
What happens is that a TaskPool thread picks up a task, does the necessary preprocessing, then sends out the network request asynchronously. This means that this task will not block while waiting for the network, but rather it releases the ThreadPool thread to pick up another workitem. When the network request completes, the tasks continuation (the remaining code lines after the network request) is scheduled back to the list of tasks.
You can see that theoretically this is the most efficient process, so fast that you have to be careful not to flood your network.
Back to Parallel.Foreach and async
At this point you should be able to spot the problem. All your async lambda async (e) => { await outEventHub.AddAsync(e);} is doing is to kick off the work, it will return right after it hits the await. (Remember that async/await is releasing threads while waiting.) Parallel.Foreach returns right after it started all of them. But nothing is awaiting these tasks! These become fire and forget, which is usually a bad practice. It is like you deleted the await Task.WhenAll call from your task example.
I hope this cleared most things for you, if not, let me know what to improve on.
Why don't you send those events asynchronously in parallel, like this:
var tasks = new List<Task>();
foreach( var e in strEvents )
{
tasks.Add(outEventHub.AddAsync(e));
}
await Task.WhenAll(tasks);
await outEventHub.FlushAsync();
I've got a WPF application that does a lot of talking to a remote server, so to keep the UI nice and responsive I put those operations in a second thread. There are a few possible, though unlikely, instances where that thread would just hang, blocking forever. Is there a simple way for me to implement a "cancel" button that doesn't involve calling thread.Abort()? I see a lot of people advise against using that, and I don't want to leave any unreleased resources. Perhaps a way to force the thread to throw an exception?
I specify in the title that this isn't a background worker because the program doesn't use those. It's already coded up with plain old threads.
I absolutely agree with comments that you need to fix what's broken, because that's the real issue, but if you can't at the moment, and need to continue operating. If you are on .Net 4.0, use the Task library. You can create a task and pass it an action that will execute on a different thread. The key is that you can pass a cancellation token to that task.
http://msdn.microsoft.com/en-us/library/dd997396.aspx
if you fire the same action over and over, you can also check the task status and do something about that.
//this is just a sample
if (myTask != null) //meaning it's still exe'ing your action
{
if (myTask.Status == TaskStatus.Faulted) //there's some kind of a problem with exe'ing it
myTask = null; // could reset to run the action again
else
return; //let the task finish
}
myTask = Task.Factory.StartNew (() =>
{
ExecuteUMyAction ();
});
I have a synchronous web service call that returns a message. I need to quickly return a message that basically says that order was received. I then need to spend a couple of minutes processing the order, but cannot block the service call for that long. So how can I return from the web service, and then do some more stuff? I'm guessing I need to fork some other thread or something before I return, but I'm not sure of the best approach.
string ProcessOrder(Order order)
{
if(order.IsValid)
{
return "Great!";
//Then I need to process the order
}
}
You can open a new thread and have it do what you need, while you're main thread returns great.
string ProcessOrder(Order order)
{
if(order.IsValid)
{
//Starts a new thread
ThreadPool.QueueUserWorkItem(th =>
{
//Process Order here
});
return "Great!";
}
}
You could start your big amount of work in a seperate thread
public string ProcessOrder(Order order)
{
if(order.IsValid)
{
System.Threading.ParameterizedThreadStart pts = new System.Threading.ParameterizedThreadStart(DoHardWork);
System.Threading.Thread t = new System.Threading.Thread(pts);
t.Start(order);
return "Great!!!";
}
}
public void DoHardWork(object order)
{
//Stuff Goes Here
}
Is the work you're doing "important?" I assume it is. You could use a thread, but you'll have to be ok with the possibility that your work might get interrupted if the machine restarts or possibly if the asp.net worker process recycles. This would likely lead to the work not getting done even though you already told the client you had accepted it. This might be or not depending on your use case.
I would consider taking the work item you receive from the synchronous service request and putting it in a persistent queue. An easy way to do this is to use a transational MSMQ queue. Your synchronous service puts the work request in the queue and you have a few worker threads pulling work requests out of the queue. Wrap your queue read and the work in a transaction and don't commit the transaction until the work is completed. If you machine or process shuts down in the middle of a request, it will be restarted automatically the next time it starts up.
You could also look at utilizing the PIAB (Policy Injection Application Block) to accomplish work after a method call.