ASP.NET Background Tasks

BackgroundTasks

On a ASP.net application, at some point you need to launch background tasks, either to analyse, manipulate or consolidate data from database, edit pictures, send newsletters… After some research, test and reading articles like (How to run Background Tasks in ASP.NET and The Dangers of Implementing Recurring Background Tasks In ASP.NET), I found a lot of solutions using .net, 3rd parties assemblies, applications which can help to run background tasks.

AppDomain

First here are some facts about ASP.net and the AppDomain of your WebApp every ASP.net developers should know:

  • Unlike an Windows executable, an ASP.net WebApp is managed by ASP.net through the IIS web server process (w3wp.exe).
  • ASP.net start your AppDomain on the first request of your WebApp.
  • When you publish a new version of your WebApp web.config, ASP.net will recycle your AppDomain (w3wp.exe will stay alive).
  • When an unhandled exception occurred in a thread not related to a request, IIS web server process (w3wp.exe) might crash, else ASP.net will display the Yellow screen of death.
  • IIS recycle w3wp.exe every 29 hours, and of course ASP.net will recycle all the AppDomain too.
  • IIS might be configure to tear down Application Pool (ASP.net) after a period of inactivity, and of course all the AppDomain linked to the Application Pool will be recycled.

So there is many things which can cause your AppDomain to be tear down; this will very important to understand some points below.

ThreadPool

Okay let’s start a new task and then… STOP Don’t do that!!!

ASP.net have no Idea of the TPL tasks you are running in background, and because the ASP.net can recycle your AppDomain at any time, your running a Task will just disappear… Pouf… No Status of success or error. just like that. So please never ever use the ThreadPool in a ASP.net WebApp to run background tasks.

IRegisteredObject

Added in .NET 4.5, HostingEnvironment.RegisterObject help to register an object, implementing IRegisteredObject, as an object managed by the hosting environment (unlike the ThreadPool). In short when it is time to for ASP.net to recycle the AppDomain, the hosting environment will give instances of IRegisteredObject 30 seconds to stop (for all, not each instances). In fact it will call Stop, the only method of IRegisteredObject, twice with 30 seconds apart.

void Stop(
   bool immediate
)
  • The first time, is to indicate the object that it need to stop; immediate will be false. The object need to stop all pending tasks, and be unregister using HostingEnvironment.UnregisterObject. This allows ASP.net to know which object he need to call a second time.
  • The second time, 30 seconds later, is to indicate the object that it need to stop NOW or else…; immediate will be true. This is the last chance, if the object has not stop all his running tasks, everything will be aborted.

QueueBackgroundWorkItem

Added in .NET 4.5.2, HostingEnvironment.QueueBackgroundWorkItem help to schedule a work item (Actions<T> of Func<T>) which will run in the background, independent of any request. QueueBackgroundWorkItem use IRegisteredObject but the second call on Stop (30 seconds after the first one) will be ignore and all work items will be simply terminated.

public ActionResult SendMails()
{
      HostingEnvironment.QueueBackgroundWorkItem(ct => SendMailsTo(ct, "Hello World"));
      return View();
}

private void SendMailsTo (CancellationToken ct, string msg)
{
      ...
      foreach (var contact in Contacts)
      {
            if (ct.IsCancellationRequested)
            {
                  break;
            }

            SendMail(contact, msg);
      }

      return ct;
}

Console Application

  • Sporadic tasks can be launch directly from the WebApp by calling the console application with a create process.
  • Recurring tasks can be schedule using Windows Task Scheduler; I used Task Scheduler Managed Wrapper from NuGet to create and manage task on the server. I added a controller (and views) to my WebApp to manage the different tasks.

For the application to know the task to do from Windows task scheduler, use parameters on the console application (better to make it a standard even if you call it from ASP.net). To avoid an outrage on your server when there is too much sporadic tasks, code the console application as single instance executable using a mutex to manage all your background tasks (recurring or not) in a central point. Therefore use a queue to manage tasks (either with a table on a database, xml…). So when the application is called, first add the task received in parameter to the tasks queue (save it), check the mutex and then process the queue if you are the only instance, run the tasks one after the other or using TPL.

Service

Create a Windows Service to manage your tasks, register it on your windows, set the start-up type to automatic. With Windows Service recurring tasks can be manage simply since the Service is always up. Like the Console Application, use a “Tasks Queue”; Tasks could be added from you WebApp directly in the “Tasks Queue” or by calling the Service with WCF (The service will be in charge of the add in the “Tasks Queue”). Finally, like the Console Application, the service will have to process the queue and run the tasks one after the other or using TPL.

Third party assemblies

There is several assemblies available on NuGet to help you run background tasks:

But the one which pick my interest is this last one HangFire; With a complete documentation of the API and some guide to help you decide which is the best settings for application. The framework is setup thanks to OWIN and propose a dashboard. It propose different type of taks (fire and forget, recurring, delayed…). It is also scalable by externalize jobs on other ASP.net servers or on windows service (thanks to this nice guide). The framework is compatible Web Garden & Web Farm environments. Hangfire use SQL Server and polling technique to fetch jobs but MSMQ or Redis extensions exists… It would go on and on, so I will test it more and create a post later.

Conclusion

So many choices, but in the end it all depend on the tasks you need to do.

Normal (<30Sec) Extended (<90Sec) Long
ThreadPool  favorites (avoid)
IRegisteredObject favorites
QueueBackgroundWorkItem favorites
Console App (+ Task Scheduler) favorites
Service favorites
HangFire favorites

 

I used nearly all methods, for long tasks my heart goes to HangFire for the scalability (process the tasks on a service), the included dashboard, the very good framework, the documentation and the guides/articles.

Check the following articles

About Cédric Cazin

Currently at Thomson Reuters, as a Lead Software Engineer, I am specialized in .Net projects (and C++) in the Eikon Desktop Team. Working on WPF and ASP.net, let me see both worlds of the Desktop and Web.

Leave a Reply