Description
Summary:
A regression in Hangfire versions after 1.8.12 introduces a subtle bug where the constructor of GlobalJobFilters is not run during initialization. This causes issues with custom global filters, such as disabling automatic retries.
Affected Versions:
Good version: 1.8.12
Bug introduced: Commit f052283 ("Sergey Odinokov 06/06/2024, 13.42 Use C# 7.3's static anonymous functions to have less allocations")
Bug present in: 1.8.18 (latest tested version)
Steps to Reproduce:
Call HangfireServiceCollectionExtensions.AddHangfire with a typical setup, for example:
.UseFilter(
new AutomaticRetryAttribute
{
Attempts = 0
});
Add a custom global filter after AddHangfire is called, for example:
Hangfire.GlobalJobFilters.Filters.Add(new HangfireJobCreationMetricAttribute(app.Services.GetRequiredService<IMonitoringClient>()));
Observe that a new AutomaticRetry filter with default retries 10 is added despite the custom filter.
Root Cause: The issue seems to stem from this line in the AddHangfire method:
services.TryAddSingleton<IJobFilterProvider>(static _ => JobFilterProviders.Providers);
Adding the static keyword prevents the constructor of GlobalJobFilters from running, leading to incomplete initialization.
Impact:
This bug causes unexpected behavior in tests and applications that rely on custom global filters, such as those that set up no automatic retry for failing jobs. For instance, tests relying on a failing Hangfire job after a set time may fail unexpectedly.
Suggested Fix:
Investigate the use of the static keyword in the lambda expression and consider reverting to a non-static version to ensure proper initialization.