HangfireIO / Hangfire

An easy way to perform background job processing in .NET and .NET Core applications. No Windows Service or separate process required
https://www.hangfire.io
Other
9.43k stars 1.71k forks source link

.NET 8 Application Dequeues Recurring Jobs without Hangfire Configuration #2398

Open shelbyneal opened 7 months ago

shelbyneal commented 7 months ago

I am noticing strange behavior when running hangfire in a .NET 8 architecture. The docs state

"You can stop processing background jobs in your main application by simply removing the instantiation of the BackgroundJobServer class (if you create it manually) or removing an invocation of the UseHangfireServer method from your OWIN configuration class."

However, I have one instance of the application that configures hangfire on startup and another that does not. If I launch both applications simultaneously, the application without startup configuration continues to dequeue recurring jobs.

Specs:

Configuration for instance A happens in the startup file:

public void ConfigureServices(IServiceCollection services)
{
  ...
  services.AddHangfire(configuration => configuration
    .SetDataCompatibilityLevel(CompatibilityLevel.Version_180)
    .UseSimpleAssemblyNameTypeSerializer()
    .UseRecommendedSerializerSettings()
    .UsePostgreSqlStorage(c => c.UseNpgsqlConnection(dbConnectionString))
  );
  services.AddHangfireServer(options => 
  {
    options.ServerName = $"{Environment.MachineName}.{instanceId}";
    options.SchedulePollingInterval = TimeSpan.FromSeconds(1);
  });
  ...
}

There is no configuration for instance B. I've removed all calls to .AddHangfire, .AddHangfireServer, and .UseHangfireDashboard. There are no calls to set storage globally.

Case A: There is at least one existing recurring job in storage

Expected behavior: start instance B, confirm no jobs are dequeued. Actual behavior: start instance B, instance B starts splitting the work with instance A.

Case B: There are no recurring jobs in storage

Expected behavior: start instance B, then schedule a recurring job from instance B for instance A to execute Actual behavior: error with stack trace

Current JobStorage instance has not been initialized yet. You must set it before using Hangfire Client or Server API. For .NET Core applications please call the `IServiceCollection.AddHangfire` extension method from Hangfire.NetCore or Hangfire.AspNetCore package depending on your application type when configuring the services and ensure service-based APIs are used instead of static ones, like `IBackgroundJobClient` instead of `BackgroundJob` and `IRecurringJobManager` instead of `RecurringJob`.

   at Hangfire.JobStorage.get_Current()
   at Hangfire.RecurringJobManager..ctor()
   at Hangfire.RecurringJob.<>c.<.cctor>b__61_0()
   at System.Lazy`1.CreateValue()
   at Hangfire.RecurringJob.AddOrUpdate(String recurringJobId, Expression`1 methodCall, String cronExpression, RecurringJobOptions options)
   at HangfireHelper.JobScheduler.ScheduleJob(JobToSchedule jobToSchedule, IDictionary`2 jobData) in C:\someProject\dotnetSolution\libraries\HangfireHelperLibrary\JobScheduler.cs:line 81

It appears the JobStorage is initialized without any kind of hangfire configuration on startup if there is a recurring job in storage. I don't understand how this is possible. The only way I see of preventing instance B from dequeuing a recurring job is to simply not start instance B. Am I perhaps missing some additional configuration somewhere?