I’m able to successfully scale out Hangfire to multiple .Net Core boxes, running simple Console.Writeline() jobs. I seem to be doing something incorrectly with registration of Hangfire Client IoC containers, or perhaps my servers are not using those configured IoC containers correctly to resolve the concrete types in constructors. I get a mixture of ‘No Type registered’ and ‘No parameterless constructor’ exceptions when the server attempts to run the job.
Has anyone been able to find code samples for scaling out Hangfire servers and clients with the Asp.Net core default IoC container?
Currently using:
“Hangfire.AspNetCore”: “1.6.6” and “Hangfire.PostgreSql.NetCore”: “1.4.3”.
Thanks!
Edit: Startup.cs Files shown. I’m sure I’m doing something incorrectly, I just don’t know where.
Code for Startup.cs Hangfire Server:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Hangfire.PostgreSql;
using Serilog;
using Hangfire.Dashboard;
namespace Hangfire.Web
{
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
//exception thrown if this is not present
services.AddHangfire(options => options
.UseStorage(new PostgreSqlStorage(Configuration["PostgresJobStoreConnectionString"]))
.UseColouredConsoleLogProvider()
//.UseActivator(AB.ISO.API.Controllers
);
services.AddSingleton<IConfiguration>(Configuration);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IApplicationLifetime appLifetime, IServiceScopeFactory scopeFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
loggerFactory.AddSerilog();
// Ensure any buffered events are sent at shutdown
appLifetime.ApplicationStopped.Register(Log.CloseAndFlush);
app.UseMvc();
//Hangfire:
//GlobalConfiguration.Configuration
// .UseStorage(new PostgreSqlStorage(Configuration["PostgresJobStoreConnectionString"]));
app.UseHangfireServer(
options: new BackgroundJobServerOptions()
{
ServerName = "AB's SERVER!",
Activator = new AB.ISO.API.IsoApiAspNetCoreJobActivator(scopeFactory) //this AspNetCoreActivator is contained in the other project, and referenced here via Nuget
},
storage: new PostgreSqlStorage(Configuration["PostgresJobStoreConnectionString"]));
app.UseHangfireDashboard("/hangfire", new DashboardOptions()
{
Authorization = new List<IDashboardAuthorizationFilter>() { new NoAuthFilter() },
StatsPollingInterval = 5000 //can't seem to find the UoM on github - assuming ms
}
);
}
}
}
And the Startup code for Hangfire client:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Hangfire;
using Hangfire.PostgreSql;
using AB.FileStore.Impl.MongoDB;
using AB.FileStore.Interfaces;
using Hangfire.AspNetCore;
namespace AB.ISO.API
{
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc()
.AddControllersAsServices();
services.AddTransient<IDbFileStorage<string>>((constructor) => new MongoDBFileStorageEngine(Configuration["FileStorage:FileStoreConnectionString"]));//file storage referenced externally via Nuget
services.AddTransient<FileDownloadJobs>();
services.AddSingleton<IConfiguration>(Configuration);
services.AddSingleton<IServiceProvider>(services.BuildServiceProvider());
// services.AddSingleton<JobActivator>(new IsoApiAspNetCoreJobActivator())
//the lambda line is sketchy - doesn't seem top stick when the job itself runs (Global Configuration error)
services.AddHangfire(config => config
.UseStorage(new PostgreSqlStorage(Configuration["Hangfire:JobStoreConnectionString"])));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IServiceProvider serviceProvider, IServiceScopeFactory scopeFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseMvc();
app.UseHangfireDashboard();
GlobalConfiguration.Configuration.UseActivator(new IsoApiAspNetCoreJobActivator(scopeFactory));
JobStorage.Current = new PostgreSqlStorage(Configuration["Hangfire:JobStoreConnectionString"]);
}
}
}