Halt and Hangfire
Tags: dotnet, csharp, hangfire, cron
Published: 2019-04-09 08:18:11

---
title: Halt and Hangfire
published: true
description: Scheduling background and recurring jobs with Hangfire
tags: dotnet, csharp, hangfire, cron
cover_image: https://thepracticaldev.s3.amazonaws.com/i/dgu92s4kegdxz1jwdn2i.gif
canonical_url: https://turnerj.com/blog/halt-and-hangfire
---
_Cover image from [Halt and Catch Fire](https://en.wikipedia.org/wiki/Halt_and_Catch_Fire_(TV_series))_

I have a website and I want to schedule a task to run every X minutes. Majority of the time, you would reach for [Cron](https://en.wikipedia.org/wiki/Cron), throw together a fancy CRON expression and you would be on your way.

This is great for a world where you deploy to a Linux server but isn't how you approach scheduling tasks on Windows. In Windows, you have the Task Scheduler and while it is powerful, I have always found it a bit cumbersome. In any case, using either Cron or Task Scheduler, you have achieved your goal of having a scheduled task run.

Now, like many projects, requirements change and you not only need a scheduled task but adhoc background tasks too. That's fine, you can work out some way of instantiating another "instance" of your code in the background to do work. It might be something dodgy like a website doing a request to itself and not waiting for a response or something as simple as running a command on the shell. Again, your problems are "solved".

Another change to requirements comes around (third times the charm, am I right?) and now you need a dashboard to view and manage these tasks...

I can't speak to how you would achieve this in other frameworks however if you are using .NET, you are in luck thanks to [Hangfire](https://www.hangfire.io/) by [Sergey Odinokov](https://twitter.com/odinserj).

# What's Hangfire?

Hangfire is a library that allows you to have both scheduled and adhoc background tasks in your application, backed by persistent storage. These tasks can then be viewed through the Hangfire dashboard to see what is running, what will run and what has failed.

![](https://thepracticaldev.s3.amazonaws.com/i/wju7gp69o0km09mvocm0.png)

Hangfire supports automatic retrying of tasks and can link into both your error logging and dependency injection systems making it easy to connect to your application.

One of my favourite features of Hangfire however is that due to how it is built, it automatically supports distributed tasks across multiple servers. With this in mind, it is good to have many small tasks to make the most use of this.

It isn't limited to ASP.NET applications either, you can have your Hangfire server be a Windows Service for all it cares!

Hangfire is free for personal and commercial use however has premium features like batching/grouping tasks together.

![](https://thepracticaldev.s3.amazonaws.com/i/ca00u4j0ncr8anjfic7h.png)

# Example

Before anything else, you will need to add [Hangfire from Nuget](https://www.nuget.org/packages?q=hangfire).

For an ASP.NET Core application, you would need to update your `ConfigureServices` method in your Startup class to include the following:

```csharp
public void ConfigureServices(IServiceCollection services)
{
	// ...

	services.AddHangfire(c =>
	{
		c.UseSqlServerStorage("YOUR_CONNECTION_STRING");
	});

	// ...
}
```

While my example is using SQL Server, Hangfire supports various other storage systems including [MongoDB](https://github.com/sergeyzwezdin/Hangfire.Mongo) or [Redis](https://www.hangfire.io/pro/#hangfireproredis).

Now in the `Configure` method of your Startup class, you need to actually trigger the server and dashboard (though dashboard is optional).

```csharp
app.UseHangfireDashboard("/hangfire");
app.UseHangfireServer();
```
Now when your application begins, the Hangfire server will start and be able to process tasks. You will also be able to view the Hangfire dashboard at the path you specified on `UseHangfireDashboard`.

So that gets the server start, what about the tasks that are meant to run in the background?

## Scheduled Tasks

In your `Configure` method in your Startup class, you will want to add something like the following for a scheduled task:

```csharp
RecurringJob.AddOrUpdate(() => Console.Write("Look ma, a recurring task!"), "0 * * * *");
```

While that is a simple example, you do need to keep your background tasks simple because the expression is serialised. With how I use Hangfire for scheduled tasks, it looks more like:

```csharp
RecurringJob.AddOrUpdate<MyBackgroundTaskClass>(instance => instance.RunTask("Whatever", "arguments", 1, "like"), "MY CRON EXPRESSION")
```
This would create an instance of `MyBackgroundTaskClass` (with DI support) and call the `RunTask` method with the specified arguments. You can pass various arguments to the tasks however for compatibility and simplicity, it is best to provide only essential arguments in the simplest form. This is because the data is serialised and some types serialise easier than others. Personally, I would pass IDs referencing items in the DB that the task should then query itself.

In that example, the class `MyBackgroundTaskClass` nor the `RunTask` method need to be anything special. They don't need special attributes or does the class need to inherit from a specific class or interface.

## Adhoc Tasks

For adhoc tasks anywhere in your application, it is just as simple:

```csharp
BackgroundJob.Enqueue<MyBackgroundTaskClass>(instance => instance.RunTask("Whatever", "arguments", 1, "like"))
```

Same rules apply like the recurring job - you will want to keep the arguments simple rather than passing through complex objects.

# Summary

Hangfire provides a simple way for you to manage background tasks, scheduled and adhoc, for your .NET application. I'm only scratching the surface in this post, there are many more nuanced pieces of functionality that make Hangfire great.

I highly recommend [going through the documentation](https://docs.hangfire.io/en/latest/getting-started/index.html) for a more in-depth dive into Hangfire.

Hope you enjoyed reading this and will give [Hangfire](https://www.hangfire.io/) a look in your next project!

![](https://media.giphy.com/media/1179nmuBk7YPg4/giphy.gif)