GlobalConfiguration class is the preferred way to configure Hangfire
For a start, the use of the word “preferred” suggests that it’s not the only way, yet there is no mention of any other options. Secondly, all the examples show the database storage being configured in that global config. Doesn’t that mean that a single assembly cannot use multiple Hangfire servers that each use a different database?
I want to use Hangfire to implement the outbox pattern, which requires that the background jobs are stored in the same DB as my domain objects. In one application I have multiple domains, each with their own DB. How can I do this if Hangfire’s DB configuration is global?
Hi Plasmadog, I’m far from an expert with Hangfire, but recently needed to do the same and was able to do it like so:
var storageOneOptions = new SqlServerStorageOptions
{
CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
QueuePollInterval = TimeSpan.Zero,
UseRecommendedIsolationLevel = true,
DisableGlobalLocks = true,
};
services.AddHangfire(configuration => configuration
.SetDataCompatibilityLevel(CompatibilityLevel.Version_170)
.UseSimpleAssemblyNameTypeSerializer()
.UseRecommendedSerializerSettings()
.UseSqlServerStorage(connectionStringToDatabaseOne, storageOneOptions));
var storageOne = new SqlServerStorage(connectionStringToDatabaseOne, storageOneOptions);
services.AddHangfireServer(
(services, options) =>
{
options.Queues = new[] { "queue1" };
options.ServerName = "ServerOne";
},
storageOne
);
// That's it for creating the server for the first one, now repeat with a different storage to create the second.
var storageTwoOptions = new SqlServerStorageOptions
{
CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
QueuePollInterval = TimeSpan.Zero,
UseRecommendedIsolationLevel = true,
DisableGlobalLocks = true,
};
services.AddHangfire(configuration => configuration
.SetDataCompatibilityLevel(CompatibilityLevel.Version_170)
.UseSimpleAssemblyNameTypeSerializer()
.UseRecommendedSerializerSettings()
.UseSqlServerStorage(connectionStringToDatabaseTwo, storageTwoOptions));
var storageTwo = new SqlServerStorage(connectionStringToDatabaseTwo, storageTwoOptions);
services.AddHangfireServer(
(services, options) =>
{
options.Queues = new[] { "queue2" };
options.ServerName = "ServerTwo";
},
storageTwo
);
// Notice that we're passing in the connection string or the SqlServerStorage to specify which database to use.
// Now, when we enqueue jobs we have to specify which database we want to use I ended up using
// a RecurringJobManager because I don't believe there's a way to specify storage just using the
// standard RecurringJob.AddOrUpdate() method.
var RecurringJobManagerOne = new RecurringJobManager(storageOne);
RecurringJobManagerOne.AddOrUpdate(....)
// Instantiate a different job manager for jobs you want to go to second db.
var RecurringJobManagerTwo = new RecurringJobManager(storageTwo);
RecurringJobManagerTwo.AddOrUpdate(....)
// If you want a dashboard, just pass in your storage - repeat for second dashboard if desired.
endpoints.MapHangfireDashboard("/hangfireOne", new DashboardOptions()
{
DashboardTitle = "Dashboard for DB One",
}, storageOne);