daily_driver
daily_driver

Reputation: 115

.NET 8 Hangfire application on IIS is not always running

I have a Hangfire application written on .NET 8 and hosted on IIS. It's used to run a daily scheduled job. Problem is that after some time the application shuts down and does not start again, so job does not run.

I did everything in the Hangfire documentation section "If nothing works for you…, but it still does not work. I recycle the app pool / restart, but application does not start again.

IIS:

installed Application Initialization module

application pool:

set .NET CLR version to 4.0
set managed pipeline mode to 4.0
set start mode to AlwaysRunning
set Idle Time-Out (minutes) to 0

site:

set Preload Enabled to true
Configuration Manager → system.webServer/applicationInitialization
From: ApplicationHost.config
set doAppInitAfterRestart to True
added hostName and initializationPage to Collection Editor

What am I missing?

Windows Server 2019, IIS version 10.

Upvotes: 0

Views: 413

Answers (1)

J.Memisevic
J.Memisevic

Reputation: 1454

You should host your hangfire server in different application - windows service for example. And use Web API just to host hangfire dashboard.

Setup would look something like this:

For Windows service:

    var hostbuilder = Host.CreateDefaultBuilder(args);
    var host = hostbuilder.UseWindowsService().
    ConfigureServices((hostContext, services) => 
    {
       var storageOptions = new SqlServerStorageOptions
     {
         CommandBatchMaxTimeout = TimeSpan.FromMinutes(30),
         SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
         QueuePollInterval = TimeSpan.Zero,
         UseRecommendedIsolationLevel = true,
         DisableGlobalLocks = true,
         EnableHeavyMigrations = true,
     };
      services.AddHangfire(c => c
         .UseSimpleAssemblyNameTypeSerializer()
         .UseRecommendedSerializerSettings()
         .UseSqlServerStorage(() => new SqlConnection(connectionString), storageOptions));
    
    services.AddHangfireServer(a =>
    {
        a.WorkerCount = Math.Min(Environment.ProcessorCount * hangfireConfiguration.WorkerCount, 10);
        a.Queues = new[] { "default", "lowprio" };
    });
    
    }).Build();

await host.RunAsync();

And for the Web API you just configure the Hangfire dashboard , use the same code from above just without adding the hangfire servers.

Something like this:

        var builder = WebApplication.CreateBuilder(args);
          var storageOptions = new SqlServerStorageOptions
             {
                 CommandBatchMaxTimeout = TimeSpan.FromMinutes(30),
                 SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
                 QueuePollInterval = TimeSpan.Zero,
                 UseRecommendedIsolationLevel = true,
                 PrepareSchemaIfNecessary = false
             };
        builder.Services..AddHangfire(c => c
                 .UseSimpleAssemblyNameTypeSerializer()
                 .UseRecommendedSerializerSettings()
                 .UseSqlServerStorage(() => new SqlConnection(connectionString), storageOptions));
        
        var app = builder.Build();
        
        var hangfireStorage = new SqlServerStorage(() => new SqlConnection(connectionString), storageOptions);
        var dashboardOptions = new DashboardOptions { Authorization = new[] { new AllowAllAuthorizationFilter() } };
        
        app.UseHangfireDashboard("/dashboard", dashboardOptions, hangfireStorage);
    await app.RunAsync();
}

    public class AllowAllAuthorizationFilter : IDashboardAuthorizationFilter
    {
        public bool Authorize(DashboardContext context)
        {
            return true;
        }
    }

PS Don't forget to use same connection string. Your server and your dashboard will look into the same database.

Achieving always on on IIS is really challenging and depends on a lot of things - this way is much easier - widows service is always running.

Upvotes: 1

Related Questions