Hangfire – Background Jobs für .NET und .NET Core Anwendungen

Viele Anwendungen benötigen Hintergrundjobs, die unabhängig von der Benutzeroberfläche ausgeführt werden können, also ohne dass ein Benutzer interagiert. Früher wurde dies häufig mit Windows Services gelöst.

Für .NET und .NET Core Anwendungen gibt es allerdings eine bessere Lösung: Hangfire (https://www.hangfire.io/)

Hangfire ist ein Open Source Framework um Background-Jobs zu erstellen und zu verwalten. Diese werden schließlich in der Datenbank gespeichert um zu gewährleisten, dass Jobs auch bei einem Neustart der Anwendung oder des Servers bestehen bleiben. Folgende Datenbank Speichersysteme werden unterstützt:

  • Microsoft SQL Server
  • Redis
  • mongoDB
  • PostgreSQL
  • C1 CMS

Erste Schritte

Zunächst müssen einige Pakete installiert werden. Entweder über die Paket-Manager-Konsole (Package-Manager-Console) oder über die NuGet-Verwaltung. Je nachdem ob es sich um eine .NET oder .NET Core Anwendung handelt, variieren diese minimal.

Installation über die NuGet-Verwaltung

Installation über die Package-Manager-Console

Install-Package Hangfire.Core

Install-Package Hangfire.SqlServer

Install-Package Hangfire.AspNet

Install-Package Hangfire.AspNetCore


dotnet add package Hangfire.Core

dotnet add package Hangfire.SqlServer

dotnet add package Hangfire.AspNet

dotnet add package Hangfire.AspNetCore

Konfiguration

Zunächst erstellst du eine Datenbank, sofern noch keine vorhanden und definierst den Connection String in der web.config Datei um eine Verbindung zwischen WebAPI und Datenbank zu gewährleisten. Anschließend musst du in der startup.cs Datei deines .NET oder .NET Core Projekts eine Verbindung zwischen Hangfire und Ihrer Datenbank herstellen.

Sample ASP.NET Core Startup class
---------------------------------

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

namespace MyWebApplication
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddHangfire(x => x.UseSqlServerStorage("DefaultConnection"));
            services.AddHangfireServer();
        }
        
        public void Configure(IApplicationBuilder app)
        {
            app.UseHangfireDashboard();
        }
    }
}


Sample OWIN Startup class
-------------------------

using Hangfire;
using Microsoft.Owin;
using Owin;

[assembly: OwinStartup(typeof(MyWebApplication.Startup))]

namespace MyWebApplication
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            GlobalConfiguration.Configuration.UseSqlServerStorage("DefaultConnection");

            app.UseHangfireDashboard();
            app.UseHangfireServer();
        }
    }
}

Nach der Ausführung deines Projekts und erfolgreicher Verbindung zur Datenbank sollten dieser folgende Tabellen hinzugefügt worden sein.

Durch UseHangfireDashboard(); in der Datei Startup.cs hat man Zugriff auf das Hangfire-Dashboard. Du erreichst es indem du deiner URL /hangfire (z.B. localhost:52184/hangfire) anhängst.

Erstellung von Hintergrundjobs

Hangfire bietet uns verschiedene Methoden an, die zur Erstellung unterschiedlicher Hintergrundjobs dienen.

Zum einen gibt es die sogenannten Fire-and-forget jobs, die unmittelbar nach der Erstellung des Projekts ausgeführt werden.

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

Delayed jobs werden ebenso einmalig ausgeführt, allerdings erst nach einem angegebenen Zeitintervall.

var jobId = BackgroundJob.Schedule(
    () => Console.WriteLine("Delayed!"),
    TimeSpan.FromDays(7));

Recurring jobs, werden immer wieder ausgeführt (z.B. stündlich, täglich, wöchentlich uvm.)

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

Continuations jobs, werden ausgeführt, wenn der Vorläufige Job beendet wurde.

BackgroundJob.ContinueWith(
    jobId,
    () => Console.WriteLine("Continuation!"));

Beispiel - Statusänderung

Im folgende Beispiel wird die Funktion ChangeStatus() minütlich ausgeführt.

RecurringJob.AddOrUpdate(() => ChangeStatus(), Cron.Minutely);

Die Funktion ChangeStatus() setzt den Status einer Umfrage auf „Aktiv“ sobald das Startdatum überschritten wurde und die Umfrage nicht bereits den Status „Aktiv“ hat.
Anschließend werden die Daten in der Datenbank gespeichert.

public void ChangeStatus()
{
	var today = DateTime.Now;
	try
	{
		var list = new List();

		using (var db = new TeamCheckEntities())
		{
			var surveysToOpen = db.Surveys.Where(s => s.Startdate <= today && s.Status.Name != DbConstants.StatusActive
			  && s.Status.Name != DbConstants.StatusClosed);
			var surveysToClose = db.Surveys.Where(s => s.Enddate <= today && s.Status.Name != DbConstants.StatusClosed);

			var statusActive = db.Status.First(s => s.Name == DbConstants.StatusActive);
			var statusClosed = db.Status.First(s => s.Name == DbConstants.StatusClosed);
			foreach (var survey in surveysToOpen)
			{
				survey.Status = statusActive;
			}
			foreach (var survey in surveysToClose)
			{
				survey.Status = statusClosed;
			}
			db.SaveChanges();
		}
	}
	catch (Exception e)
	{
		throw;
	}
}