Introduction
Hangfire is a powerful open-source library that enables background job processing in .NET applications. It allows developers to schedule and execute jobs asynchronously without requiring a separate service or Windows service.
Hangfire integrates seamlessly with ASP.NET Core and supports job persistence via SQL Server, Redis, and other storage providers.
When working with Hangfire, naming jobs effectively can improve observability, debugging, and maintainability. In this post, we’ll explore different ways to label Hangfire jobs using attributes, method parameters, and manual job creation.
Why Naming Jobs Matters
Assigning meaningful names to Hangfire jobs helps with:
- Better visibility in the Hangfire dashboard.
- Easier debugging when tracking job execution.
- Improved logging by making job types easily identifiable.
Using JobDisplayName
Attribute
The [JobDisplayName]
attribute allows you to specify a human-readable name for a job.
public class MyJob
{
[JobDisplayName("This is my job")]
public void Run() { }
}
Enqueueing this job:
backgroundJobs.Enqueue<MyJob>(x => x.Run());
Using Parameters in Job Names
You can include method parameters in job names using placeholders:
public class MyJob2
{
[JobDisplayName("{0}")]
public void Run(string name) { }
}
Enqueueing this job:
backgroundJobs.Enqueue<MyJob2>(x => x.Run("Custom Job Name"));
Multiple Parameters in Job Names
If your method has multiple parameters, you can specify which one should be used in the job name by specifying the parameter index.
public class MyJobWithPayload
{
[JobDisplayName("{1}")]
public void Run(MyPayload payload, string jobName) { }
}
Enqueueing this job:
backgroundJobs.Enqueue<MyJobWithPayload>(x => x.Run(new MyPayload(), "My Custom Job Name"));
Manually Naming Jobs
If you need to create jobs dynamically, you can set job names when enqueuing them:
backgroundJobs.Create(
new Job(typeof(MyJobManual), typeof(MyJobManual).GetMethod(nameof(MyJobManual.Run))),
new EnqueuedState()
);
For jobs with parameters:
backgroundJobs.Create(
new Job(typeof(MyJobManualWithArgument), typeof(MyJobManualWithArgument).GetMethod(nameof(MyJobManualWithArgument.Run)), "Manual Job Name"),
new EnqueuedState()
);
Naming Jobs in Generic Handlers
When working with generic job handlers, you can use the same {0}
placeholder pattern:
public class EnqueueJobHandler<TPayload> where TPayload : class
{
[JobDisplayName("{0}")]
public async Task Process(TPayload payload)
{
await _serviceProvider.GetRequiredService<IJobHandler<TPayload>>().Handle(payload);
}
}
This allows the job name to be dynamically set based on the ToString()
implementation of TPayload
.
public record PayloadExtended(Guid Id) : Payload(Id)
{
public override string ToString() => $"Payload Processing ({Id})";
}
Enqueueing a job with this handler:
backgroundJobs.Enqueue<EnqueueJobHandler<PayloadExtended>>(x => x.Process(new PayloadExtended(Guid.NewGuid())));
Conclusion
Effectively naming Hangfire jobs can significantly improve the observability and manageability of your background processing system. Whether using attributes, dynamic placeholders, or manually setting names, each approach has its use case. Choosing the right method depends on your specific needs for job tracking and debugging.
Have you found other useful ways to name Hangfire jobs?