QueueBackgroundWorkItem vs. Task.Run for background task - c#

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??

Related

Why console applications do not have SynchronizationContext? [duplicate]

I'm trying to learn more about the SynchronizationContext, so I made this simple console application:
private static void Main()
{
var sc = new SynchronizationContext();
SynchronizationContext.SetSynchronizationContext(sc);
DoSomething().Wait();
}
private static async Task DoSomething()
{
Console.WriteLine(SynchronizationContext.Current != null); // true
await Task.Delay(3000);
Console.WriteLine(SynchronizationContext.Current != null); // false! why ?
}
If I understand correctly, the await operator captures the current SynchronizationContext then posts the rest of the async method to it.
However, in my application the SynchronizationContext.Current is null after the await. Why is that ?
EDIT:
Even when I use my own SynchronizationContext it is not captured, although its Post function is called. Here is my SC:
public class MySC : SynchronizationContext
{
public override void Post(SendOrPostCallback d, object state)
{
base.Post(d, state);
Console.WriteLine("Posted");
}
}
And this is how I use it:
var sc = new MySC();
SynchronizationContext.SetSynchronizationContext(sc);
Thanks!
The word "capture" is too opaque, it sounds too much like that is something that the framework is supposed to. Misleading, since it normally does in a program that uses one of the default SynchronizationContext implementations. Like the one you get in a Winforms app. But when you write your own then the framework no longer helps and it becomes your job to do it.
The async/await plumbing gives the context an opportunity to run the continuation (the code after the await) on a specific thread. That sounds like a trivial thing to do, since you've done it so often before, but it is in fact quite difficult. It is not possible to arbitrarily interrupt the code that this thread is executing, that would cause horrible re-entrancy bugs. The thread has to help, it needs to solve the standard producer-consumer problem. Takes a thread-safe queue and a loop that empties that queue, handling invoke requests. The job of the overridden Post and Send methods is to add requests to the queue, the job of the thread is to use a loop to empty it and execute the requests.
The main thread of a Winforms, WPF or UWP app has such a loop, it is executed by Application.Run(). With a corresponding SynchronizationContext that knows how to feed it with invoke requests, respectively WindowsFormsSynchronizationContext, DispatcherSynchronizationContext and WinRTSynchronizationContext. ASP.NET can do it too, uses AspNetSynchronizationContext. All provided by the framework and automagically installed by the class library plumbing. They capture the sync context in their constructor and use Begin/Invoke in their Post and Send methods.
When you write your own SynchronizationContext then you must now take care of these details. In your snippet you did not override Post and Send but inherited the base methods. They know nothing and can only execute the request on an arbitrary threadpool thread. So SynchronizationContext.Current is now null on that thread, a threadpool thread does not know where the request came from.
Creating your own isn't that difficult, ConcurrentQueue and delegates help a lot of cut down on the code. Lots of programmers have done so, this library is often quoted. But there is a severe price to pay, that dispatcher loop fundamentally alters the way a console mode app behaves. It blocks the thread until the loop ends. Just like Application.Run() does.
You need a very different programming style, the kind that you'd be familiar with from a GUI app. Code cannot take too long since it gums up the dispatcher loop, preventing invoke requests from getting dispatched. In a GUI app pretty noticeable by the UI becoming unresponsive, in your sample code you'll notice that your method is slow to complete since the continuation can't run for a while. You need a worker thread to spin-off slow code, there is no free lunch.
Worthwhile to note why this stuff exists. GUI apps have a severe problem, their class libraries are never thread-safe and can't be made safe by using lock either. The only way to use them correctly is to make all the calls from the same thread. InvalidOperationException when you don't. Their dispatcher loop help you do this, powering Begin/Invoke and async/await. A console does not have this problem, any thread can write something to the console and lock can help to prevent their output from getting intermingled. So a console app shouldn't need a custom SynchronizationContext. YMMV.
By default, all threads in console applications and Windows Services only have the default SynchronizationContext.
Kindly refer to the MSDN article Parallel Computing - It's All About the SynchronizationContext. This has detailed information regarding SynchronizationContexts in various types of applications.
To elaborate on what was already pointed out.
The SynchronizationContext class that you use in the first code snippet is the default implementation, which doesn't do anything.
In the second code snippet, you create your own MySC context. But you are missing the bit that would actually make it work:
public override void Post(SendOrPostCallback d, object state)
{
base.Post(state2 => {
// here we make the continuation run on the original context
SetSynchronizationContext(this);
d(state2);
}, state);
Console.WriteLine("Posted");
}
Implementing your own SynchronizationContext is doable, but not trivial. It's much easier to use an existing implementation, like the AsyncContext class from the Nito.AsyncEx.Context package. You can use it like this:
using System;
using System.Threading;
using System.Threading.Tasks;
using Nito.AsyncEx;
public static class Program
{
static void Main()
{
AsyncContext.Run(async () =>
{
await DoSomethingAsync();
});
}
static async Task DoSomethingAsync()
{
Console.WriteLine(SynchronizationContext.Current != null); // True
await Task.Delay(3000);
Console.WriteLine(SynchronizationContext.Current != null); // True
}
}
Try it on Fiddle.
The AsyncContext.Run is a blocking method. It will complete when the supplied asynchronous delegate Func<Task> action completes. All asynchronous continuations are going to run on the console application's main thread, provided that there is no Task.Run or ConfigureAwait(false) that would force your code to exit the context.
The consequences of using a single-threaded SynchronizationContext in a console application are that:
You'll no longer have to worry about thread-safety, since all your code will be funneled to a single thread.
Your code becomes susceptible to deadlocks. Any .Wait(), .Result, .GetAwaiter().GetResult() etc inside your code is very likely to cause your application to freeze, in which case you'll have to kill the process manually from the Windows Task Manager.

Why the default SynchronizationContext is not captured in a Console App?

I'm trying to learn more about the SynchronizationContext, so I made this simple console application:
private static void Main()
{
var sc = new SynchronizationContext();
SynchronizationContext.SetSynchronizationContext(sc);
DoSomething().Wait();
}
private static async Task DoSomething()
{
Console.WriteLine(SynchronizationContext.Current != null); // true
await Task.Delay(3000);
Console.WriteLine(SynchronizationContext.Current != null); // false! why ?
}
If I understand correctly, the await operator captures the current SynchronizationContext then posts the rest of the async method to it.
However, in my application the SynchronizationContext.Current is null after the await. Why is that ?
EDIT:
Even when I use my own SynchronizationContext it is not captured, although its Post function is called. Here is my SC:
public class MySC : SynchronizationContext
{
public override void Post(SendOrPostCallback d, object state)
{
base.Post(d, state);
Console.WriteLine("Posted");
}
}
And this is how I use it:
var sc = new MySC();
SynchronizationContext.SetSynchronizationContext(sc);
Thanks!
The word "capture" is too opaque, it sounds too much like that is something that the framework is supposed to. Misleading, since it normally does in a program that uses one of the default SynchronizationContext implementations. Like the one you get in a Winforms app. But when you write your own then the framework no longer helps and it becomes your job to do it.
The async/await plumbing gives the context an opportunity to run the continuation (the code after the await) on a specific thread. That sounds like a trivial thing to do, since you've done it so often before, but it is in fact quite difficult. It is not possible to arbitrarily interrupt the code that this thread is executing, that would cause horrible re-entrancy bugs. The thread has to help, it needs to solve the standard producer-consumer problem. Takes a thread-safe queue and a loop that empties that queue, handling invoke requests. The job of the overridden Post and Send methods is to add requests to the queue, the job of the thread is to use a loop to empty it and execute the requests.
The main thread of a Winforms, WPF or UWP app has such a loop, it is executed by Application.Run(). With a corresponding SynchronizationContext that knows how to feed it with invoke requests, respectively WindowsFormsSynchronizationContext, DispatcherSynchronizationContext and WinRTSynchronizationContext. ASP.NET can do it too, uses AspNetSynchronizationContext. All provided by the framework and automagically installed by the class library plumbing. They capture the sync context in their constructor and use Begin/Invoke in their Post and Send methods.
When you write your own SynchronizationContext then you must now take care of these details. In your snippet you did not override Post and Send but inherited the base methods. They know nothing and can only execute the request on an arbitrary threadpool thread. So SynchronizationContext.Current is now null on that thread, a threadpool thread does not know where the request came from.
Creating your own isn't that difficult, ConcurrentQueue and delegates help a lot of cut down on the code. Lots of programmers have done so, this library is often quoted. But there is a severe price to pay, that dispatcher loop fundamentally alters the way a console mode app behaves. It blocks the thread until the loop ends. Just like Application.Run() does.
You need a very different programming style, the kind that you'd be familiar with from a GUI app. Code cannot take too long since it gums up the dispatcher loop, preventing invoke requests from getting dispatched. In a GUI app pretty noticeable by the UI becoming unresponsive, in your sample code you'll notice that your method is slow to complete since the continuation can't run for a while. You need a worker thread to spin-off slow code, there is no free lunch.
Worthwhile to note why this stuff exists. GUI apps have a severe problem, their class libraries are never thread-safe and can't be made safe by using lock either. The only way to use them correctly is to make all the calls from the same thread. InvalidOperationException when you don't. Their dispatcher loop help you do this, powering Begin/Invoke and async/await. A console does not have this problem, any thread can write something to the console and lock can help to prevent their output from getting intermingled. So a console app shouldn't need a custom SynchronizationContext. YMMV.
By default, all threads in console applications and Windows Services only have the default SynchronizationContext.
Kindly refer to the MSDN article Parallel Computing - It's All About the SynchronizationContext. This has detailed information regarding SynchronizationContexts in various types of applications.
To elaborate on what was already pointed out.
The SynchronizationContext class that you use in the first code snippet is the default implementation, which doesn't do anything.
In the second code snippet, you create your own MySC context. But you are missing the bit that would actually make it work:
public override void Post(SendOrPostCallback d, object state)
{
base.Post(state2 => {
// here we make the continuation run on the original context
SetSynchronizationContext(this);
d(state2);
}, state);
Console.WriteLine("Posted");
}
Implementing your own SynchronizationContext is doable, but not trivial. It's much easier to use an existing implementation, like the AsyncContext class from the Nito.AsyncEx.Context package. You can use it like this:
using System;
using System.Threading;
using System.Threading.Tasks;
using Nito.AsyncEx;
public static class Program
{
static void Main()
{
AsyncContext.Run(async () =>
{
await DoSomethingAsync();
});
}
static async Task DoSomethingAsync()
{
Console.WriteLine(SynchronizationContext.Current != null); // True
await Task.Delay(3000);
Console.WriteLine(SynchronizationContext.Current != null); // True
}
}
Try it on Fiddle.
The AsyncContext.Run is a blocking method. It will complete when the supplied asynchronous delegate Func<Task> action completes. All asynchronous continuations are going to run on the console application's main thread, provided that there is no Task.Run or ConfigureAwait(false) that would force your code to exit the context.
The consequences of using a single-threaded SynchronizationContext in a console application are that:
You'll no longer have to worry about thread-safety, since all your code will be funneled to a single thread.
Your code becomes susceptible to deadlocks. Any .Wait(), .Result, .GetAwaiter().GetResult() etc inside your code is very likely to cause your application to freeze, in which case you'll have to kill the process manually from the Windows Task Manager.

Does QueueBackgroundWorkItem actually queue background work?

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.

WCF service blocking the UI thread even though CallbackBehavior attribute is defined

I'm using a WCF service in a .Net 4.0 WPF application and I'm observing a call to a WCF service blocking updates on the UI thread even though it has the UseSynchronizationContext = false defined on the service class.
The following code does not block the UI when the Thread.Sleep() is included but when the call to api.GetFieldExpressionAssemblies() is included instead it blocks updates to the UI.
This code is being executed on a background thread and has been scheduled using the Reactive extensions method ObserveOn() with the task pool scheduler.
.ObserveOn(Scheduler.TaskPool)
.Select(x =>
{
var api = factory.Create();
using (new Duration())
{
//Thread.Sleep(5000);
//return new Dictionary<string, string[]>();
return ExtractIntellisense(api.GetFieldExpressionAssemblies().Single());
}
})
Rx version = 1.0.10621.2, this is an old version of Rx and I'm aware of issues with scheduling work onto the task pool with this version of the Rx scheduler, but the fact the Thread.Sleep() does not block the UI thread indicates this is not the issue.
Any ideas why this might happen?
My psychic debugger says that if you wrapped this code in a Task.Run it would work. Rx is working fine here, but WCF is capturing a synchronization context at the point you're creating the Observable, which is probably the UI thread, because WCF is dumb.
I have been able to prove the problem is not with binding the results from the WCF because the following code still block the UI even though the results returned from the WCF are not actually returned from the Rx chain.
This points to trying what Paul suggested.
.ObserveOn(SchedulerService.TaskPool)
.Select(x =>
{
var api = factory.Create();
using (new Duration())
{
var intellisenseDictionary = ExtractIntellisense(api.GetFieldExpressionAssemblies().Single());
//return intellisenseDictionary;
return new Dictionary<string, string[]>();
}
So the answer as usual is a simple one, someone had changed the WCF service ConcurrencyMode to Single, requests were being processed in a serial manner.
Which backs up what I was seeing - but with a small difference, the UI thread was not blocked I could still move the window round and it was being redrawn, just the data was not appearing.
WCF sucks!

Task.Run() does not runs asynchronously

I have an ASP.NET MVC 3 site that connects to a WCF service. The WCF Service is independent from the site and is hosted in a Windows Service.
Most of the calls are synchronous, so it's not a problem to wait for the WCF to do it's thing.
However, one of those (already implemented) calls takes a bit too long, and, as it essentially does not output anything directly, I wanted to spin it on the service and forget about it.
So I changed my code from:
public ViewResult StartSlowCalculation(CalculationOptions calculationOptions)
{
WcfServiceProxy.DoSlowCalculation(calculationOptions);
ViewBag.Started = true;
return View();
}
to
public ViewResult StartSlowCalculation(CalculationOptions calculationOptions)
{
Task.Run(() =>
{
WcfServiceProxy.DoSlowCalculation(calculationOptions);
});
ViewBag.Started = true;
return View();
}
which, as I understand should start an asynchronous request, and return immediately. Still, the execution is completely synchronous, and the UI is frozen until the operation concludes.
What obvious thing am I missing?
Update:
Also, note that I would prefer not to change the server implementation to an async one, just to de-synchronize the call to the service on the call-site.
Moreover, I've noticed that the StartSlowCalculation method finishes executing, but the server does not return a response until the service method finishes executing.
The WCF Service Proxy just does:
public void DoSlowCalculation(CalculationOptions calculationOptions)
{
//some logging code
Channel.DoSlowCalculation(calculationOptions);
}
so it's completely synchronous, however that shouldn't matter as it should be executed on an independent thread.
A task operation can run in the calling thread, it depends on taskScheduler decision. To help TaskScheduler make a right decision regarding long running call you can specify task creation option TaskCreationOptions.LongRunning.
And you can check whether task operation is running in a separate thread:
int launchedByThreadId = Thread.CurrentThread.ManagedThreadId;
int launchedInThreadId = -1;
Task.Run(() =>
{
launchedInThreadId = Thread.CurrentThread.ManagedThreadId;
WcfServiceProxy.DoSlowCalculation(calculationOptions);
});
// then compare whether thread ids are different
BTW, are you using any kind of Task.Wait() operation? It will block calling thread as well.
EDIT:
You might find following post interesting Is Task.Factory.StartNew() guaranteed to use another thread than the calling thread?
So try out using Task.Factory.StartNew() and specify cancellation token even you do not need it, sounds weird but it seems this guarantees that task will not be run eventually in the calling thread. Correct me If I wrong.
I've done this before.
The most robust way would be to use Asynchronous Controller's, or better yet an independant service such as a WCF service.
But in my experience, i've just needed to do "simple", one-liner task, such as auditing or reporting.
In that example, the easy way - fire off a Task:
public ViewResult StartSlowCalculation(CalculationOptions calculationOptions)
{
//Some Synchronous code.
Task.Factory.StartNew(() =>
{
WcfServiceProxy.DoSlowCalculation(calculationOptions);
});
ViewBag.Started = true;
return View();
}
That's a simple example. You can fire off as many tasks as you want, synchronize them, get notified when they finish, etc.
For more details you can see this links.
https://msdn.microsoft.com/en-us/library/dd321439(v=vs.110).aspx

Categories