Hangfire

Dosaic.Plugins.Jobs.Hangfire is a plugin that allows Dosaic-based services to schedule and manage background jobs using Hangfirearrow-up-right. It supports recurring (cron) jobs, fire-and-forget jobs, delayed jobs, PostgreSQL or in-memory storage, a built-in dashboard, OpenTelemetry tracing, Prometheus metrics, and feature-flag-based job execution control.

Installation

dotnet add package Dosaic.Plugins.Jobs.Hangfire

or add as a package reference to your .csproj:

<PackageReference Include="Dosaic.Plugins.Jobs.Hangfire" Version="" />

Configuration

Configure appsettings.yml (or appsettings.json) with the hangfire section:

hangfire:
  # PostgreSQL storage (ignored when inMemory: true)
  host: localhost
  port: 5432
  database: postgres
  user: postgres
  password: postgres

  # Use in-memory storage instead of PostgreSQL (useful for development)
  inMemory: true

  # Hostname from which the Hangfire dashboard is accessible.
  # Leave empty to disable dashboard access entirely.
  allowedDashboardHost: localhost

  # Enable Microsoft Feature Management integration to toggle jobs via config
  enableJobsByFeatureManagementConfig: false

  # Additional queues to listen on (the "default" queue is always included)
  queues:
    - default
    - critical

  # Optional tuning
  pollingIntervalInMs: 5000       # defaults to Hangfire built-in value
  workerCount: 10                 # defaults to Hangfire built-in value
  invisibilityTimeoutInMinutes: 30
  maxJobArgumentsSizeToRenderInBytes: 4096  # max bytes of job args displayed in dashboard

Configuration class reference

Usage

Defining jobs

Simple async job (no parameters)

Extend AsyncJob and implement ExecuteJobAsync:

Parameterized async job

Extend ParameterizedAsyncJob<T> when the job requires input:

Note: Job input parameters and results are serialized to JSON and displayed in the Hangfire dashboard. Avoid passing sensitive data as job parameters.

Registering recurring jobs

Option 1 — attribute-based auto-registration

Annotate the job class with [RecurringJob]. The plugin discovers and registers it automatically at startup — no boilerplate required:

The [RecurringJob] attribute accepts a standard cron expression and an optional queue name.

Option 2 — programmatic registration via ConfigureJobs

Register jobs in your plugin or host configuration using the IJobManager API:

Fire-and-forget and delayed jobs via IJobManager

Inject IJobManager to enqueue or schedule jobs programmatically at runtime:

Querying job state via IJobManager

IJobManager exposes monitoring APIs to inspect the current state of the job store:

Dashboard

The Hangfire dashboard is mounted at /hangfire. Access is restricted to the host configured in allowedDashboardHost. If the value is empty or not set, access is denied for all hosts.

Attributes

[RecurringJob(cronPattern, queue)]

Marks a class for automatic recurring job registration at startup. Accepts a cron pattern and an optional queue name.

[JobTimeout(timeout, TimeUnit)]

Cancels the job after the specified duration. The cancellation token passed to ExecuteJobAsync is cancelled automatically.

Supported TimeUnit values: Milliseconds, Seconds, Minutes, Hours, Days.

[JobTimeZone(TimeZoneInfo)]

Specifies the time zone used for cron schedule evaluation of recurring jobs (default: UTC).

[UniquePerQueueAttribute(queue)]

Prevents duplicate job executions. If a job with the same type and arguments is already queued, the new one is deleted instead of enqueued.

Optional properties:

  • CheckScheduledJobs — also check scheduled (delayed) jobs (default: false)

  • CheckRunningJobs — also check currently processing jobs (default: false)

[JobCleanupExpirationTimeAttribute(days)]

Controls how many days job results are retained in the storage backend before deletion.

Filters

LogJobExecutionFilter (always active)

Automatically logs a structured message at the start and finish of every job execution using the job's own logger type.

EnabledByFeatureFilter (opt-in)

Gates job execution on a feature flag using the Microsoft Feature Managementarrow-up-right system. Enable via configuration:

Works with both file-based feature management and the Dosaic Unleash pluginarrow-up-right for dynamic runtime feature flags. Since the flag is resolved before each job execution, changes take effect at runtime with a delay based on how frequently the feature management source is refreshed.

Custom storage / server configuration (IHangfireConfigurator)

Implement IHangfireConfigurator (a IPluginConfigurator) to plug in a custom Hangfire storage backend or to configure the background server options:

All IHangfireConfigurator implementations are discovered automatically by the Dosaic plugin system.

Observability

Health check

A Hangfire readiness health check is registered automatically and is accessible via the standard Dosaic health endpoints (/health/readiness). It verifies that at least one Hangfire server is running.

OpenTelemetry tracing

Hangfire jobs are automatically instrumented with OpenTelemetry tracing via OpenTelemetry.Instrumentation.Hangfire.

Prometheus metrics

A background service (HangfireStatisticsMetricsReporter) collects Hangfire statistics every 60 seconds and publishes them as OpenTelemetry gauges:

Metric
Description

hangfire_job_count_Succeeded

Number of succeeded jobs

hangfire_job_count_Failed

Number of failed jobs

hangfire_job_count_Scheduled

Number of scheduled (delayed) jobs

hangfire_job_count_Processing

Number of currently processing jobs

hangfire_job_count_Enqueued

Number of enqueued jobs

hangfire_job_count_Deleted

Number of deleted jobs

hangfire_job_count_Recurring

Number of registered recurring jobs

hangfire_job_count_Servers

Number of active Hangfire servers

hangfire_job_count_Queues

Number of active queues

hangfire_job_count_RetryJobs

Number of jobs currently awaiting retry

Job naming convention

The job ID used by Hangfire is derived from the class name by stripping the Job and Async suffixes. For example:

  • SendDailyReportJobSendDailyReport

  • ProcessOrderAsyncJobProcessOrder

When registering the same job type multiple times with jobSuffix, the suffix is appended: ProcessOrder_v2.

Further reading

Last updated