Monitor Hangfire recurring jobs
Hangfire retries failed jobs and shows them on its dashboard, which is helpful only if someone opens it. When the Hangfire server isn’t running, a job keeps failing through its retries, or the recurring job was removed in a deploy, nobody is told. A heartbeat check catches all of these: the job reports to Pingstack after it succeeds, and Pingstack alerts you when that report doesn’t arrive on time.
1. Create a heartbeat check that matches the schedule
Section titled “1. Create a heartbeat check that matches the schedule”Find the recurring job’s registration:
RecurringJob.AddOrUpdate<NightlyReportJob>( "nightly-report", job => job.RunAsync(), "0 2 * * *", new RecurringJobOptions { TimeZone = TimeZoneInfo.Utc });Create a heartbeat check and set its
schedule to Cron with the same expression. Hangfire uses UTC unless you
set TimeZone; choose the same timezone in Pingstack. See
schedules and timezones.
Set a grace period that covers the job’s runtime and its retries. Hangfire retries a failed job automatically, with growing delays, so a job that succeeds on a later attempt can report much later. Attach a notification group.
2. Store the ping URL in configuration
Section titled “2. Store the ping URL in configuration”Copy the location’s ping URL from the check in Pingstack and provide it as
configuration, such as the environment variable Pingstack__NightlyReportUrl
in production or dotnet user-secrets in development. Don’t put it in
appsettings.json.
3. Report after the job succeeds
Section titled “3. Report after the job succeeds”public class NightlyReportJob( IReportService reports, IHttpClientFactory httpFactory, IConfiguration config, ILogger<NightlyReportJob> log){ public async Task RunAsync() { await reports.SendNightlyAsync();
var url = config["Pingstack:NightlyReportUrl"]; if (string.IsNullOrEmpty(url)) return;
try { var http = httpFactory.CreateClient(); http.Timeout = TimeSpan.FromSeconds(10); (await http.GetAsync(url)).EnsureSuccessStatusCode(); } catch (Exception e) when (e is HttpRequestException or TaskCanceledException) { log.LogWarning("Pingstack heartbeat failed: {Error}", e.GetType().Name); } }}The report runs only after SendNightlyAsync() completes, so a run that
throws sends nothing and Pingstack alerts you when the deadline passes. A
failure to reach Pingstack is logged, not thrown, so it can’t make Hangfire
retry a successful job. Register IHttpClientFactory with
builder.Services.AddHttpClient().
4. Confirm the first report
Section titled “4. Confirm the first report”Open the Hangfire dashboard, go to Recurring Jobs, select the job and choose Trigger now. When it succeeds, open the check in Pingstack and confirm the location received a heartbeat and shows a next deadline.
Optional: report a number
Section titled “Optional: report a number”Append a count as a numeric value and set warning and critical thresholds on the check:
var sent = await reports.SendNightlyAsync();await http.GetAsync($"{url}?value={sent}");Why a healthy job might still alert
Section titled “Why a healthy job might still alert”- Retries. A job that succeeds on its fourth attempt reports hours late.
Either lengthen the grace period or reduce retries for this job with
[AutomaticRetry(Attempts = 2)]. - No server. Recurring jobs are queued but not run if no Hangfire server is processing that queue.
- Timezone mismatch. The check and
RecurringJobOptions.TimeZonemust agree.
If alerts still don’t match what you expect, see troubleshooting monitoring.