Zwei der meistgelesenen Threads im Hangfire-Forum sind „Enqueued Jobs starten nicht mit der Verarbeitung" und „Jobs werden in der Datenbank erstellt, stecken als Enqueued fest." Zusammen rund 40.000 Aufrufe. Das Muster ist immer gleich: das Dashboard zeigt eine wachsende Liste von Jobs im Status Enqueued, kein Processing, kein Failed, kein Fehler irgendwo — und niemand merkt es, bis ein Kunde fragt, warum sein nächtlicher Report nicht lief.
Dass Jobs im Status Enqueued bleiben, bedeutet eines: kein Worker holt sie ab. Die Job-Zeilen existieren im Storage und warten auf ihren Einsatz, aber der Worker-Pool, der sie abarbeiten sollte, ist weg, festgefahren oder nie gestartet. Es gibt kein Failed-Event, weil nichts tatsächlich versucht und fehlgeschlagen ist — die Queue wird einfach nicht abgearbeitet. Die häufigsten Root-Causes:
BackgroundJobServer läuft nicht mehr, also gibt es nichts, das dequeued. Hangfire emittiert kein „Worker gestoppt"-Event; die Queue hört einfach auf, abzuarbeiten.WorkerCount-Fehlkonfiguration. Ein Server mit konfiguriertem Worker-Pool von 0 (manchmal ein Tippfehler in der Deployment-Config) enqueuet stillschweigend alles und verarbeitet nichts. Kein Fehler, kein Log-Eintrag."critical" enqueued, der Server hört nur auf "default". Kein Worker wird ihn je abholen. Subtil und häufig — besonders wenn verschiedene Teams für Enqueue und Worker zuständig sind.Der Impuls ist, das Hangfire-Dashboard zu prüfen. Das Problem ist, dass das Dashboard im selben Prozess läuft wie die Jobs — wenn der Prozess krank ist, ist auch das Dashboard krank. Wenn der App-Pool recycled wurde, ist das Dashboard weg. Wenn der Worker-Pool gesättigt ist, konkurrieren die eigenen Requests des Dashboards mit demselben gesättigten Pool. Ein Dashboard, an das man denken muss, es zu laden, in einem Prozess, der vielleicht nicht läuft, ist keine Monitoring-Lösung — es ist ein Debugging-Tool, das man benutzt, nachdem jemand es schon bemerkt hat.
Was man eigentlich braucht, ist ein externer Beobachter — etwas, das in einem anderen Prozess läuft und den Event-Stream auf „Jobs werden enqueued, aber nichts bewegt sich nach Processing" überwacht. Das ist das Queue-Backlog-Alert-Muster: ein Alarm feuert, wenn das Verhältnis von Enqueued zu Processing über ein Zeitfenster falsch läuft, unabhängig davon, warum.
Bevor man etwas baut, hier das SQL, das sagt, ob man gerade einen Backlog hat (SQL Server-Variante; PostgreSQL geht analog mit anderer Datumssyntax):
SELECT TOP 20
j.Id,
j.StateName,
s.Data,
s.CreatedAt
FROM Hangfire.Job j
LEFT JOIN Hangfire.State s ON s.Id = j.StateId
WHERE j.StateName = 'Enqueued'
ORDER BY s.CreatedAt DESC;
Wenn die neueste Enqueued-Zeile Stunden alt ist und keine Processing-Zeilen im selben Fenster existieren, hat man einen Backlog. Die Query funktioniert, weil sie am Dashboard vorbeigeht und direkt die Storage-Tabellen fragt — aber jemand muss sie trotzdem ausführen. Das ist die Lücke.
Die saubere Trennung ist dieselbe wie bei der Historien-Retention: nicht den eigenen Prozess von Hangfire fragen, ob der eigene Prozess von Hangfire kaputt ist. Die State-Changes in etwas streamen, das unabhängig läuft, und dieses auf das Muster alarmieren lassen.
Hier setzt QueueHawk an. Der Agent streamt jeden Enqueued-, Processing-, Succeeded- und Failed-Übergang per HTTPS heraus, sobald er passiert — unabhängig davon, ob der Hangfire-Serverprozess selbst gesund ist. Eine Alert-Regel, die den Stream überwacht, kann auf „N Events in den letzten M Minuten enqueued, null nach Processing" feuern — genau das Muster, das bedeutet, dass ein Worker weg ist. Der Alarm landet in Slack, Teams oder E-Mail, bevor der Kunde es bemerkt.
WorkerCount-Fehlkonfiguration, Assembly-Lade-Fehler auf nicht-referenzierendem Server, Queue-Name-Mismatch.Siehe auch: Slack-/Teams-/E-Mail-Alerts bekommen, wenn ein Hangfire-Job fehlschlägt oder verstummt für die Alert-Auslieferungs-Seite davon, und Hangfire über mehrere Kundenprojekte hinweg überwachen dafür, warum das mit jedem weiteren Projekt schlimmer wird.
Kostenlos für eine Application, keine Kreditkarte nötig.