After a long development, batches and batch continuations are completed, and I’m glad to introduce these features. It was a real challenge for me and for Hangfire to implement these features as a regular extension. If you don’t share my joy (Batches? Why I need them?), I’ll show you why they are so important.

Atomic Background Job Creation

Batches allow you to create a bunch of background jobs atomically. This means that if there was an exception during the creation of background jobs, none of them will be processed. Consider you want to send 1000 emails to your clients, and they really want to receive these emails. Here is the old way:

for (var i = 0; i < 1000; i++)
    BackgroundJob.Enqueue(() => SendEmail(i));
    // What to do on exception?

But what if storage become unavailable on i == 500? 500 emails may be already sent, because worker threads will pick up and process jobs once they created. If you re-execute this code, some of your clients may receive annoying duplicates. So if you want to handle this correctly, you should write more code to track what emails were sent.

But here is a much simpler method:

Configuration required

Before using batches, please call the GlobalConfiguration.Configuration.UseBatches method as written in the docs.

BatchJob.StartNew(x =>
    for (var i = 0; i < 1000; i++)
        x.Enqueue(() => SendEmail(i));

In case of exception, you may show an error to a user, and simply ask to retry her action after some minutes. No other code required!

Chaining Batches

Continuations allow you to chain multiple batches together. They will be executed once all background jobs of a parent batch finished. Consider the previous example where you have 1000 emails to send. If you want to make final action after sending, just add a continuation:

var id1 = BatchJob.StartNew(/* for (var i = 0; i < 1000... */);
var id2 = BatchJob.ContinueWith(id, x => 
    x.Enqueue(() => MarkCampaignFinished());
    x.Enqueue(() => NotifyAdministrator());

So batches and batch continuations allow you to define workflows and configure what actions will be executed in parallel. This is very useful for heavy computational methods as they can be distributed to a different machines.

Complex Workflows

Create action does not restrict you to create jobs only in Enqueued state. You can schedule jobs to execute later, add continuations, add continuations to continuations, etc..

var batchId = BatchJob.StartNew(x =>
    x.Enqueue(() => Console.Write("1a... "));
    var id1 = x.Schedule(() => Console.Write("1b... "), TimeSpan.FromSeconds(1));
    var id2 = x.ContinueWith(id1, () => Console.Write("2... "));
    x.ContinueWith(id2, () => Console.Write("3... "));

BatchJob.ContinueWith(batchId, x =>
    x.Enqueue(() => Console.WriteLine("4..."));


As other parts of Hangfire, batches are fully transparent, so you can observe them in the Dashboard. Here is a list of started batches, for example:

Batch List

And this is a batch details page, that is like job details, but for batches. You can see all the data related to a batch as well as all related background jobs.

Batch Details


Batches are available in the Hangfire.Pro package, and you can install it using NuGet Package Manager Console window as usually:

PM> Install-Package Hangfire.Pro

Batches require to add some additional job filters, some new pages to the Dashboard, and some new navigation menu items. But thanks to the new GlobalConfiguration class, it is now as simple as a one method call:

Only Hangfire.SqlServer and Hangfire.Pro.Redis job storage implementations are currently supported. There is nothing special for batches, but some new storage methods should be implemented. I'll contact job storage authors, but don't know any estimates.

Only in Pro

Batches are a part of Hangfire Pro package set and available onдн for Hangfire Pro subscribers.

Subscribe to monthly updates

Subscribe to receive monthly blog updates. Very low traffic, you are able to unsubscribe at any time.