Hangfire 1.6 just released with experimental .NET Core platform support, deep integration with ASP.NET Core and async/await programming model support. Start processing background jobs with ease even on Linux and OS X today!

Async Methods for Background Jobs

Async programming became very popular in .NET a long time ago. With the await keyword it won an even greater success – some libraries even don’t provide synchronous API (like Microsoft.Net.Http), so we can’t ignore this movement. In the past you had to await your methods manually, but those days are over.

Support for the await Keyword

The await keyword is fully supported in background methods now. So you can replace all the methods that were required to run async methods synchronously (Task.Wait, AsyncContext, etc.). Big thanks to @tuespetre for the initial implementation of this feature!

public static async Task HighlightAsync(int snippetId)
{
    var snippet = await _dbContext.CodeSnippets.SingleOrDefaultAsync(x => x.Id == snippetId);
    if (snippet == null) return;

    snippet.HighlightedCode = await HighlightSourceAsync(snippet.SourceCode);
    snippet.HighlightedAt = DateTime.UtcNow;

    await _dbContext.SaveChangesAsync();
}

If you want to return a result, use the Task<T> as a returning type instead. Please note that async void methods aren’t supported, and an exception will be thrown at runtime. This was implemented to reduce the number of issues, because async void methods can’t be awaited.

The enqueueing logic is the same for sync and async methods. In early betas there was a warning CS4014, but now you can remove all the #pragma warning disable statements. It was implemented by using Expression<Func<Task>> parameter overloads.

BackgroundJob.Enqueue(() => HighlightAsync(snippet.Id));

Cancellation Tokens

If your async methods support CancellationToken parameters, don’t forget to add them to allow background processing server to stop gracefully during the application shutdown. With this release Hangfire is able to pass CancellationToken instance to your methods.

public static async Task HighlightAsync(int snippetId, CancellationToken token)
{
     // ...
}

When creating a background job, pass whatever CancellationToken you want, but it’s better to use the CancellationToken.None to not to confuse anyone.

BackgroundJob.Enqueue(() => HighlightAsync(snippetId, CancellationToken.None));

That’s not a real asynchrony

Please consider this feature as a syntactic sugar. Background processing hasn’t became asynchronous. Internally it was implemented using the Task.Wait method, so workers don’t perform any processing, while waiting for a task completion. Real asynchrony may come in Hangfire 2.0 only, and it requires a lot of breaking changes to the existing types.

Experimental .NET Core Support

Experimental support for .NET Core platform was added in this release by targeting .NET Standard 1.3 platform. We aren’t able to run automatic tests for Hangfire yet, because some required packages weren’t ported to .NET Core (like Moq), so some edge cases may not work. All the tests should be running automatically on Windows, Linux and OS X in a near future to remove the experimental warning. Unit tests are now running automatically on Travis CI and AppVeyor, covering Windows, Linux and OS X!

Client API, Server API and Dashboard UI are working fine, please see the http://coredemo.hangfire.io/ sample. It’s hosted in a Digital Ocean’s droplet based on Ubuntu 14.04 with no Windows involved at all! Please note that some packages like Hangfire.Dashboard.Authorization are not available for .NET Core platform yet.

ASP.NET Core Integration

Dashboard UI was abstracted from OWIN to support new ASP.NET Core’s HTTP abstractions natively and move away from the OWIN dependency. The new Hangfire.AspNetCore package enables deep integration with ASP.NET Core applications for both .NET 4.5.1 and .NET Core platforms, including:

All you need is to install the new package via NuGet.

Install-Package Hangfire.AspNetCore

Configuration logic is as simple as always – there are extension methods for IServiceCollection and IApplicationBuilder interfaces.

using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Hangfire;

namespace MyWebApplication
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            // Configures Hangfire with the following methods exposed on 
            // the IGlobalConfiguration interface, and registers all the
            // required classes, including logging and DI, using new DI 
            // abstraction.
            services.AddHangfire(x => x.UseSqlServerStorage("<connection string>"));
        }
        
        public void Configure(IApplicationBuilder app)
        {
            // app.AddLogger...

            // Creates and starts a new background job server instance,
            // and registers an application stop handler for graceful
            // shutdown.
            app.UseHangfireServer();

            // Enables the Dashboard UI middleware to listen on `/hangfire`
            // path string.
            app.UseHangfireDashboard();

            // MVC app.UseMvc...
        }
    }
}

… And More!

  • Zero-latency processing when client and server reside in the same process when using SQL Server (by @bgurmendi).
  • Access to background job context from the JobActivator.BeginScope method.
  • Add LatencyTimeoutAttribute To delete jobs if timeout is exceeded (by @Excommunicated).
  • Ability to change statistics polling interval in dashboard (by @tristal).
  • SqlServerStorage class constructor now takes DbConnection instances (by @tystol).

For the whole list please see the corresponding GitHub release.

Upgrading

I’ve tried hard to not to introduce breaking changes for current users. As a result, only some Dashboard UI’s classes and interfaces were deprecated, but still available till Hangfire 2.0. Other types were not changed in Hangfire that target the .NET 4.5 platform.

IAuthorizationFilter interface was deprecated and replaced with the more abstract IDashboardAuthorizationFilter interface. To avoid warning messages, consider updating your filters to the new interface, and use the following property to enable them:

app.UseHangfireDashboard("/hangfire", new DashboardOptions
{
    Authorization = new [] { new MyAuthorizationFilter() }
});

IRequestDispatcher interface was also replaced with the IDashboardDispatcher one, and this change caused some methods of RouteCollection class to be deprecated. Please see the obsolete warning messages, they will tell you what type or method to use.

Thank You!

And last, but definitely not least, big thanks to the following folks for their help in making Hangfire even better!

Subscribe to monthly updates

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

Comments