Search code examples
iis.net-8.0hangfirewindows-server-2019

.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.


Solution

  • 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.