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:
- Dashboard UI – new middleware that is based on the Microsoft.AspNetCore.Http.Abstractions allows to use it in ASP.NET Core applications without additional dependencies.
-
Logging – the package provides
ILogProvider
interface implementation that uses Microsoft.Extensions.Logging library. -
Dependency Injection – implementation of the
JobActivator
class based on Microsoft.Extensions.DependencyInjection package is used by default.
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 takesDbConnection
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!
-
Geir Sagberg (@geirsagberg) – Cron expressions for regular intervals for the
Cron
class, PR #174. -
@Excommunicated – Add
LatencyTimeoutAttribute
To delete jobs if timeout is exceeded, PR #188. - Tris (@tristal) – Ability to change statistics polling interval in dashboard, PR #484.
-
Julien Roncaglia (@vbfox) –
SqlServerObjectsInstaller
class is public now, PR #485. -
@arnoldasgudas –
IRecurringJobManager
interface for theRecurringJobManager
class, PR #491. - Beñat Gurmendi (@bgurmendi) – Zero latency processing when client and server reside in the same process, PR #520.
- Jordi Martínez (@Elph) – Multilanguage support in Dashboard via resource files & Spanish localization for the Dashboard UI, PR #521.
-
@patrykpiotrmarek –
ToGenericTypeString
method now supports nested classes, PR #522. -
Tyson (@tystol) –
SqlServerStorage
class constructor now takesDbConnection
instances, PR #539. - Derek (@tuespetre) – Ability to create jobs based on async methods, they are awaited by a worker, PR #540.
- @teodimache – Enable backtracking from background job to recurrent job, PR #555.
- Roeland Nieuwenhuis (@ranieuwe) – Drop constraints on Server.Id prior to altering it to avoid conflicts, PR #603 (sorry for not including to NuGet).