en / de
AI
Expertisen
Methoden
Dienstleistungen
Referenzen
Jobs & Karriere
Firma
Technologie-Trends TechCast WebCast TechBlog News Events Academy

Background Jobs mit Hangfire

Ausgangslage

In modernen Softwareprojekten entstehen zahlreiche Aufgaben, die nicht im unmittelbaren Ausführungspfad der Anwendung laufen dürfen sei es ein Web-Request in ASP.NET, ein Button-Klick in einer Desktop-App, der Start eines Konsolenprogramms oder der Loop eines Windows- oder Linux-Services. Zu solchen Aufgaben gehören etwa der Versand von E-Mails, Datenaufbereitungen, automatisierte Exporte/Importe, Reports oder regelmässige Wartungsaufgaben. Solche Prozesse laufen im Hintergrund und genau dort beginnen oft die Herausforderungen.

In vielen Unternehmen werden Hintergrundprozesse zunächst selbst implementiert, oft über einen einfachen BackgroundService oder eigene Threads. Mit zunehmender Komplexität treten jedoch schnell typische Herausforderungen auf. So stellt sich zum Beispiel die Frage, wie Aufgaben zuverlässig in eine Queue eingereiht werden können, ohne dass sie bei einem Neustart oder Absturz der Anwendung verloren gehen. Ebenso ist es alles andere als trivial, wiederkehrende Abläufe wie zum Beispiel tägliche Bereinigungsjobs oder stündliche Synchronisationen sauber umzusetzen, ohne selbst eine fehleranfällige Timer- oder Scheduler-Logik entwickeln zu müssen.

Auch das Thema Fehlertoleranz spielt eine grosse Rolle. Sobald ein Job während der Ausführung scheitert, muss sichergestellt sein, dass er automatisch erneut gestartet wird, ohne dass Entwickler manuell eingreifen müssen. Noch komplexer wird es, wenn mehrere Worker oder Server parallel dieselben Hintergrundaufgaben abarbeiten sollen. Ohne geeignete Koordination besteht die Gefahr, dass Jobs doppelt ausgeführt werden oder sich Prozesse gegenseitig blockieren.

Zusätzlich fehlt in selbst gebauten Lösungen häufig die Möglichkeit, den Zustand der Jobs zentral zu überwachen. Man weiß oft nicht genau, welche Aufgaben noch ausstehen, welche fehlgeschlagen sind oder welche gerade verarbeitet werden. Und schließlich spielt Persistenz eine entscheidende Rolle. Hintergrundaufgaben müssen auch dann erhalten bleiben, wenn die Anwendung neu gestartet wird, zum Beispiel nach einem Deployment oder einem Serverausfall.

Diese Herausforderungen machen deutlich, dass eine robuste, fehlertolerante und gut überwachbare Infrastruktur für Hintergrundprozesse alles andere als trivial ist. Genau aus diesem Grund bieten spezialisierte Frameworks wie Hangfire in vielen Projekten einen erheblichen Mehrwert.

Hangfire

Hangfire ist ein Open-Source-Framework für .NET, das es ermöglicht, Hintergrundjobs innerhalb einer Webapplikation oder eines beliebigen .NET-Hostprozesses auszuführen. Das Besondere daran: Hangfire benötigt keinen separaten Windows Service oder externe Worker es läuft direkt im Prozess der Anwendung oder in einem eigenen Host, wenn man das möchte. Dabei stellt Hangfire sicher, dass alle Jobs persistiert, zuverlässig verarbeitet, überwacht und wiederaufgenommen werden können.

Ein grosser Vorteil ist die Benutzerfreundlichkeit: Die Hangfire-API ist intuitiv und reduziert komplexe Hintergrundlogik auf wenige Codezeilen. Ein Job wird beispielsweise wie folgt gestartet:

BackgroundJob.Enqueue(() => Console.WriteLine("Hello Hangfire!"));

Unter der Haube speichert Hangfire jeden Job in einer Datenbank, indem der komplette Methodenaufruf inklusive aller Parameter serialisiert wird. Dadurch liegen sowohl der Methodennamen als auch alle übergebenen Argumente dauerhaft in einem stabilen Format vor. Genau diese Serialisierung stellt sicher, dass ein Job auch nach einem Neustart der Anwendung oder einem Serverabsturz nicht verloren geht.

Worker-Instanzen lesen den serialisierten Aufruf aus der Datenbank, deserialisieren die Parameter und führen den Job aus.

Konzepete von Hangfire

Um Hangfire effizient einzusetzen, lohnt sich ein Blick auf seine wichtigsten Konzepte und Jobtypen. Diese sind bewusst einfach gehalten, decken aber nahezu alle praktischen Szenarien ab.

Fire-and-Forget Jobs

Fire-and-Forget-Jobs werden exakt einmal ausgeführt und zwar so früh wie möglich. Diese Jobs sind ideal für Aufgaben, die nicht im Request-Kontext ausgeführt werden sollen, wie etwa das Versenden einer E-Mail nach der Registrierung.

Beispiel:

BackgroundJob.Enqueue(() => service.SendWelcomeMail("[email protected]"));

Delayed Jobs

Manchmal soll ein Job nicht sofort starten, sondern erst nach einem definierten Zeitintervall. Kein Problem: Delayed Jobs planen sich selbstständig für die Zukunft ein.

BackgroundJob.Schedule(() => service.GenerateReport(), TimeSpan.FromHours(2));

Typische Szenarien sind Erinnerungsfunktionen, länger laufende Verarbeitungen oder Backoff-Strategien.

Recurring Jobs

Recurring Jobs sind wiederkehrende Tasks, ähnlich einem Cronjob. Sie eignen sich perfekt für tägliche Reports, nächtliche Datenbereinigung, stündliche Health-Checks oder regelmässige Synchronisationsprozesse.

RecurringJob.AddOrUpdate("daily-cleanup", () => service.CleanupTempFiles(), Cron.Daily);

Hangfire nutzt dafür Cron-Ausdrücke und erlaubt eine flexible Steuerung – von minütlich bis jährlich.

Continuations

Continuations sind Folgejobs, die ausgelöst werden, nachdem ein anderer Job erfolgreich abgeschlossen wurde. Sie eignen sich hervorragend für mehrstufige Workflows.

var idJob1 = BackgroundJob.Enqueue(() => service.Step1());
BackgroundJob.ContinueJobWith(idJob1, () => service.Step2());

So lassen sich komplexe Vorgänge einfach orchestrieren.

Standardmäßig wird die Fortsetzung nicht ausgeführt, solange der vorherige Job nicht erfolgreich abgeschlossen ist. Ein Fehler in Step1 führt also dazu, dass Step2 automatisch blockiert bleibt. Hangfire versucht den fehlgeschlagenen Auftrag mehrfach erneut auszuführen, abhängig von den globalen Retry-Einstellungen oder den Attributen am Job.

Queues

Für die Priorisierung und Skalierung können Jobs verschiedenen Queues zugewiesen werden. Grosse oder kritische Aufgaben können so getrennt behandelt werden. Worker können für spezifische Queues konfiguriert werden – ideal für verteilte Architekturen.

Konfiguration von Hangfire in einer .NET Core Web Application

Die Integration von Hangfire in eine .NET-Anwendung ist überraschend unkompliziert. Ein paar Konfigurationsschritte reichen bereits aus.

1. Installation via NuGet:

Install-Package Hangfire
Install-Package Hangfire.AspNetCore

2. Registrierung in der ServiceCollection:

Im Program.cs wird Hangfire nun eingebunden. Es kann dabei gewählt werden ob für die persistierung der Jobdaten eine Datenbankanbindung verwendet wird oder ob die Jobdaten in Memory gelegt werden.

Hier das Beispiel mit einer Datenbank:

services.AddHangfire(config =>
{
config.UseSqlServerStorage("Server=.;Database=HangfireDemo;Trusted_Connection=True;");
});

services.AddHangfireServer();

Wenn Hangfire in einer .NET-Anwendung eingebunden wird und eine relationale Datenbank wie SQL Server zur Persistierung der Jobs verwendet, benötigt der zugreifende Datenbankbenutzer lediglich die üblichen Rechte, um Tabellen anzulegen und Daten zu lesen oder zu schreiben.

Beim ersten Start legt Hangfire automatisch alle benötigten Strukturen in der Datenbank an. Dazu gehören Tabellen für die eigentlichen Jobs, deren Parameter und Statusverläufe, außerdem Bereiche zur Verwaltung von Queues, aktiven Workern und wiederkehrenden Aufträgen. Zusätzlich erzeugt das Framework einige Hilfstabellen, die für Locking, Statistiken und interne Koordination erforderlich sind. Alle diese Tabellen folgen einem klaren Namensschema und werden ohne manuellen Eingriff vollständig eingerichtet.

Für den Entwickler bedeutet das: Sobald Hangfire korrekt konfiguriert ist und ein Benutzer mit ausreichenden Datenbankrechten zur Verfügung steht, kümmert sich das Framework vollständig selbstständig um die Persistierung. Die Jobdaten bleiben dadurch stabil gespeichert und überstehen sowohl Neustarts als auch Fehlerfälle ohne zusätzlichen Aufwand.

3. Monitoring

Das Dashboard dient der Überwachung, Analyse und Fehlerdiagnose. Es lässt sich über Middleware aktivieren:

app.UseHangfireDashboard("/hangfire");

Das Dashboard bietet detaillierte Einblicke:

Authorization

Damit das Hangfire-Dashboard nicht oeffentlich zugaenglich ist, sollte fruehzeitig eine passende Autorisierung eingebaut werden. Das Dashboard zeigt nicht nur interne Informationen wie Methodennamen und Parameter, sondern erlaubt auch direkte Eingriffe in den Jobablauf wie das Loeschen oder erneute Ausfuehren von Jobs. Standardmaessig duerfen daher nur lokale Anfragen zugreifen. In einer produktiven Umgebung wird ueblicherweise ein eigener Authorization-Filter hinterlegt, der entscheidet, ob ein Benutzer Zugriff erhaelt. Dazu wird eine Klasse erstellt, die das Interface IDashboardAuthorizationFilter implementiert und in der Authorize-Methode prueft, ob der aktuelle Benutzer authentifiziert oder berechtigt ist. Anschliessend wird dieser Filter ueber die DashboardOptions an UseHangfireDashboard uebergeben, sodass nur angemeldete oder entsprechend autorisierte Benutzer das Dashboard oeffnen koennen. Fuer ASP.NET Core stellt Hangfire zudem eine einfache Integration ueber den aktuellen HttpContext bereit. Auf diese Weise laesst sich der Zugriff flexibel an das bestehende Sicherheitskonzept der Anwendung anpassen und sicher absichern.

Weiter Informationen dazu finden Sie hier

Fehlerbehandlung

Fehler in Hintergrundprozessen sind unvermeidbar, zum Beispiel durch Netzwerkprobleme, gesperrte Ressourcen oder unvollständige Daten. Hangfire stellt für solche Situationen einen robusten Mechanismus bereit, der sicherstellt, dass fehlgeschlagene Jobs nicht verloren gehen, sondern kontrolliert wieder aufgenommen werden. Wie ein Job neu gestartet wird und welche Verantwortung beim Entwickler liegt, ist ein zentraler Teil einer stabilen Fehlerstrategie.

Automatisches Wiederaufnehmen fehlgeschlagener Jobs

Wenn ein Job während seiner Ausführung einen Fehler auslöst, markiert Hangfire ihn als fehlgeschlagen und legt einen entsprechenden Eintrag im Statusverlauf ab. Abhängig von der Konfiguration wird der Job anschliessend automatisch erneut ausgeführt. Da Hangfire den Zustand der Jobs persistent in der Datenbank speichert, können fehlgeschlagene Aufgaben auch nach einem Neustart der Anwendung zuverlässig weitergeführt werden. Entwickler müssen daher keine eigene Wiederholungslogik schreiben, solange sie die integrierten Mechanismen nutzen.

Retry-Mechanismen und deren Konfiguration

Hangfire bringt einen integrierten Retry-Mechanismus mit, der fehlgeschlagene Jobs mehrfach neu startet, meist mit wachsendem Abstand zwischen den Versuchen. Dieses Verhalten kann global oder pro Job angepasst werden, zum Beispiel über das AutomaticRetry-Attribut. Auf diese Weise lässt sich festlegen, wie viele Wiederholungen ein Job erhalten soll oder ob automatische Retries für bestimmte Aufgaben komplett deaktiviert werden. Die Wiederholungslogik funktioniert zuverlässig über mehrere Worker hinweg und auch über Neustarts der Anwendung.

Idempotenz und Transaktionen innerhalb eines Jobs

Ob ein Job idempotent ist oder transaktional arbeiten soll, liegt in der Verantwortung des Entwicklers. Hangfire selbst führt Jobs lediglich aus und kann nicht erkennen, ob eine wiederholte Ausführung zu unerwünschten Nebeneffekten führt. Es ist daher ratsam, Jobs so zu entwerfen, dass sie entweder beliebig oft ausgeführt werden können, ohne fehlerhafte oder doppelte Ergebnisse zu erzeugen, oder dass kritische Abschnitte innerhalb einer Transaktion laufen.

Learnings aus der Praxis

Im täglichen Einsatz von Hangfire in echten Projekten zeigen sich immer wieder typische Herausforderungen, die in der Theorie kaum sichtbar sind, in der Praxis aber sehr relevant werden. Zwei besonders häufige Themen betreffen das Handling grosser Parameterobjekte und das saubere Abbrechen laufender Tasks. Beide lassen sich mit einfachen Strategien löse, sofern man sie früh berücksichtigt.

1. Parameter-Handling mit grossen Objekten

Hangfire serialisiert jeden Job-Aufruf inklusive seiner Parameter. Das bedeutet:
Je grösser das Objekt, desto grösser die Datenmenge in der Hangfire-Datenbank oder des lokalen Speichers

Best Practice:
Keine grossen Objekte direkt an Hangfire-Jobs übergeben.
Stattdessen sollte man über einen Key oder Identifier arbeiten und das Objekt zur Laufzeit neu aus einer Cache- oder Datenquelle laden.

2. Canncellation von laufenden Jobs

Hangfire unterstützt zwar „Delete Job“ über das Dashboard oder den JobClient, aber das bedeutet nicht, dass ein laufender Job wirklich abgebrochen wird. Damit werden nur noch nicht gestartete Jobs abgebrochen, laufenden Jobs werden zu Ende ausgeführt.

Best Practice:
Arbeite mit einem shared CancellationToken, der extern gesetzt werden kann, ebenfalls über IMemoryCache wie in folgendem Beispiel gezeigt.

CancellationToken in den Cache ablegen:

var cancelKey = Guid.NewGuid().ToString();
var cts = new CancellationTokenSource();
_cache.Set(cancelKey, cts, TimeSpan.FromHours(1));
BackgroundJob.Enqueue<LongJobService>(x => x.Run(cancelKey));

CancellationToken aus dem Cache beziehen:

public class LongJobService
{
    private readonly IMemoryCache _cache;
    private readonly ILogger<LongJobService> _logger;

    public LongJobService(IMemoryCache cache, ILogger<LongJobService> logger)
    {
        _cache = cache;
        _logger = logger;
    }

    public void Run(string cancelKey)
    {
        if (!_cache.TryGetValue(cancelKey, out CancellationTokenSource cts))
        {
            _logger.LogWarning("Cancel token not found, job cannot be controlled.");
            return;
        }

        var token = cts.Token;

        for (int i = 0; i < 10000; i++)
        {
            if (token.IsCancellationRequested)
            {
                _logger.LogInformation("Job was canceled.");
                return;
            }

            DoWorkStep(i);
        }

        _logger.LogInformation("Job completed successfully.");
    }

    private void DoWorkStep(int step)
    {
        Thread.Sleep(100); // simuliert Arbeit
    }
}

Vor- & Nachteile

Wie jedes Framework bringt auch Hangfire Stärken und Schwächen mit sich. In vielen Projekten ist es eine hervorragende Lösung für Hintergrundprozesse, doch abhängig von Architektur, Skalierungsanforderungen oder Infrastruktur können auch Herausforderungen entstehen. Die folgende Übersicht hilft dabei, Hangfire korrekt einzuordnen und die passende Entscheidung für ein Projekt zu treffen.

Vorteile

Nachteile

Fazit

Hangfire ist ein mächtiges Framework für Hintergrundverarbeitung in .NET. Die einfache Integration, das Dashboard, die Persistenz und die Retry-Mechanismen machen es zu einer sehr attraktiven Option für Enterprise-Anwendungen.

Es bringt jedoch Grenzen mit sich insbesondere bei Serialisierung, Task-Abbruch und hochfrequenten Event-Szenarien.
Mit den richtigen Best Practices lässt es sich jedoch sehr robust und performant betreiben.

Kommentare

Schreiben Sie einen Kommentar

Ihre E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Newsletter - aktuelle Angebote, exklusive Tipps und spannende Neuigkeiten

 Jetzt anmelden

Copyright © 2025 Noser Engineering AG – Alle Rechte vorbehalten.

NACH OBEN
Privacy Policy Cookie Policy
Zur Webcast Übersicht