How to start background process in Asp.net

I needed to start a background process in ASP.NET. The question arose: how best to do this? Googling a bit on the SCOTT HANSELMAN blog , I found the entry “ How to run Background Tasks in ASP.NET ”. The article is not very new - 2014, but quite relevant, so I decided to translate it into Russian.

A few years ago, Phil Haack wrote an excellent article about the dangers of running background tasks in ASP.NET. He identified three main risks associated with starting a background process:

  1. An unhandled exception in a thread that is not associated with the request may remove the process.
  2. If you run the site in a web farm, then there is a chance of accidentally terminating multiple instances of the application that could run multiple instances of the same task at the same time.
  3. The application domain in which the site is running, for various reasons, can unload and remove the background task running in it.

Of course, you can write your own manager to manage background tasks. But, most likely, you will do it wrong. No one is going to challenge your developer skills. Just creating such a manager is a pretty subtle thing. And why do you need it?

There are many great options for running tasks in the background. And not just abstract techniques, but ready-made libraries.

Some ASP.NET applications can run on your own servers under IIS, some can be hosted in Azure.

To start background tasks, you can select several options:

  • Basic: Hangfire or a similar library that you can use to write background tasks on your own ASP.NET site.
  • Cloud: Azure WebJobs Azure Web Jobs. A native service in Azure that you can use to run background tasks outside of your website with the ability to scale the load.
  • Advanced: Azure Web Role in Cloud Services . A service that allows you to run background tasks regardless of your site, with the ability to scale the load and control execution.

There are a large number of articles and videos on the web about how to use Azure tasks and how web roles work in Azure cloud services. But there are not many articles on how to run background tasks on your own server.

WEBBACKGROUNDER


As the site says: “WebBackgrounder is a test of the concept of a web-farm-compatible background task manager that should work only with ASP.NET web applications.” Its code has not changed for many years, but the NuGet package has been downloaded more than half a million times.

The project allows you to work with only one task, manage repetitive tasks in the background while the web application is running.

This library is clearly not for all occasions. But if while running an ASP.NET application you need to run only one task, then WebBackgrounder is all you need.

using System;
using System.Threading;
using System.Threading.Tasks;
namespace WebBackgrounder.DemoWeb
{
    public class SampleJob : Job
    {
        public SampleJob(TimeSpan interval, TimeSpan timeout)
            : base("Sample Job", interval, timeout)
        {
        }
        public override Task Execute()
        {
            return new Task(() => Thread.Sleep(3000));
        }
    }
}

Added in .NET 4.5.2 QUEUEBACKGROUNDWORKITEM


We can say that QueueBackgroundWorkItem was added in .NET 4.5.2 in response to the appearance of WebBackgrounder. This is not just an implementation of Task.Run. This is more than that:

QBWI manages scheduled tasks to run in the background, regardless of any request. The difference with the regular ThreadPool element is that ASP.NET automatically keeps track of how many work items registered with the API are currently running, and if the application domain is turned off, the ASP.NET runtime tries to defer it, making it possible to shut down the running background tasks.

Keep in mind that the ASP.NET runtime can delay the shutdown of the application domain for only 90 seconds, making it possible to complete tasks. Therefore, if you cannot complete the tasks during this time, then you need to use other, more reliable means.

The API is very simple - use Func". The following is a small example that starts a background process from an MVC:

public ActionResult SendEmail([Bind(Include = "Name,Email")] User user)
{
    if (ModelState.IsValid)
    {
       HostingEnvironment.QueueBackgroundWorkItem(ct => SendMailAsync(user.Email));
       return RedirectToAction("Index", "Home");
    }
    return View(user);
}

FLUENTSCHEDULER


FluentScheduler is a more advanced and sophisticated task manager with a fluent interface. With it, you can really control the process of launching a task.

using FluentScheduler;
public class MyRegistry : Registry
{
    public MyRegistry()
    {
        // Запуск задачи ITask через определенный интервал времени
        Schedule().ToRunNow().AndEvery(2).Seconds();
        // Запуск простой задачив определенный момент времени 
        Schedule(() => Console.WriteLine("Timed Task - Will run every day at 9:15pm: " + DateTime.Now)).ToRunEvery(1).Days().At(21, 15);
        // Запуск более сложного действия – запуск задачи немедленно и с месячным интервалом
        Schedule(() =>
        {
            Console.WriteLine("Complex Action Task Starts: " + DateTime.Now);
            Thread.Sleep(1000);
            Console.WriteLine("Complex Action Task Ends: " + DateTime.Now);
        }).ToRunNow().AndEvery(1).Months().OnTheFirst(DayOfWeek.Monday).At(3, 0);
    }
}

FluentScheduler also supports IoC and can be easily connected using your favorite Dependency Injection library, simply by implementing its ITaskFactory interface.

It should be noted that FluentScheduler can work with .NET Core.

To handle exceptions that occur in background tasks, you can use the JobException event of the JobManager object. The event allows you to get information about the exception that occurred in the task.

JobManager.JobException += (info) => Log.Fatal("An error just happened with a scheduled job: " + info.Exception);

QUARTZ.NET


Quartz.NET is a version of the popular Java framework implemented in .NET. The framework is actively developing. To create a background task, Quartz uses the IJob interface with the only Execute method, which must be implemented.

using Quartz;
using Quartz.Impl;
using System;
namespace ScheduledTaskExample.ScheduledTasks
{
    public class JobScheduler
    {
        public static void Start()
        {
            IScheduler scheduler = StdSchedulerFactory.GetDefaultScheduler();
            scheduler.Start();
            IJobDetail job = JobBuilder.Create().Build();
            ITrigger trigger = TriggerBuilder.Create()
                .WithDailyTimeIntervalSchedule
                  (s =>
                     s.WithIntervalInHours(24)
                    .OnEveryDay()
                    .StartingDailyAt(TimeOfDay.HourAndMinuteOfDay(0, 0))
                  )
                .Build();
            scheduler.ScheduleJob(job, trigger);
        }
    }
}

To start the manager inside Application_Start, you need to call JobScheduler.Start (). To get started, you can read Scheduled Actions and Quartz.NET (a translation of Scheduled Tasks In ASP.NET With Quartz.Net ).

The project has pretty decent documentation, which you should read before you start using it (at least, you should look at Tutorials for Developing with Quartz ).

HANGFIRE


And the last in the review, but certainly not the least in terms of functionality, the most advanced of all Hangfire. This is really a very advanced background task framework in ASP.NET. Optionally, it can use Redis, SQL Server, SQL Azure, MSMQ or RabbitMQ to increase the reliability of task execution.

The Hangfire documentation is really excellent. I would like every open source project to have such documentation.

One of the most spectacular features of Hangfire is the built-in dashboard, which allows you to view schedules, completed tasks, and successful and unsuccessful completed tasks.

Hangfire makes it easy to identify tasks such as "run and forget", information about which will be stored in the database:

BackgroundJob.Enqueue(() => Console.WriteLine("Fire-and-forget"));

You can delay the task:

BackgroundJob.Schedule(() => Console.WriteLine("Delayed"), TimeSpan.FromDays(1));

Or run a task in CRON style

RecurringJob.AddOrUpdate(() => Console.Write("Recurring"), Cron.Daily);

Working with Hangfire is very convenient. Hangfire has good documentation and tutorials based on real world examples.

Hangfire is an entire ecosystem for working with background tasks in ASP.NET applications.

Libraries are available as open source or nuget packages.

Results (personally from myself)


Choosing a library for myself, on the one hand, I want to have decent functionality, and on the other, I don’t want to use, for example, a database to store information about running tasks. Therefore, I did not even consider simple solutions like WebBackgrounder or QueueBackgroundWorkItem.

I already know that I need to start more than one process, and processes can work for a long time (90 seconds limit for completion in QueueBackgroundWorkItem). FluentScheduler looks good, but I wanted more. Hangfire is a great solution, but it seems that it immediately requires the use of a database to store the task queue. And it’s not completely there that everything is free - there is a paid version.

In the end, I chose Quartz.NET so far: quite a decent documentation, enough examples to quickly start using, as well as extensible functionality that can be added as needs increase.

If you know other libraries for launching background tasks or have experience in solving such problems - share in the comments.

Also popular now: