2 Separate Hangfire instances using the same database

queues
recurring
Tags: #<Tag:0x00007f69fceba588> #<Tag:0x00007f69fceba420>

#1

Hi

We have 2 APIs that have nothing in common running Hangfire, but both APIs and Hangfire use the same database.
The APIs have their own schemas but the two Hangfire instances are using the same tables etc.

We are creating our background job servers the following way

backgroundJobServer = new BackgroundJobServer(new BackgroundJobServerOptions
{
    Queues = new [] { QueueName }
});

Where each instance have their own QueueName e.g: "Q1" and "Q2".

Jobs are scheduled the following way

RecurringJob.AddOrUpdate<IService>("J1", s => s.DoJob(), Cron.Weekly(DayOfWeek.Monday, 01), TimeZoneInfo.Local, QueueName);

On top of that the method invoked on the service is also decorated with the [QueueAttribute], if not requeue through the web interface queues the job on the default queue.

public interface IService
{
    [Queue(HangfireConfig.QueueName)]
    Task DoJob();
}

Here is the conundrum

API1
	HF1
		Q1
			J1

API2
	HF2
		Q2
			J2

As you can see Iv tried to illustrate two APIs having their own Hangfire (HF) instances running with their own specified queues Q1 and Q2 where J1 is scheduled in Q1 and J2 is scheduled on Q2.

Still the HF2 instance tried to schedule the J1 job that should only run on the Q1 queue which HF2 is not supposed to run and vice versa by the HF1 instance.

This results in the following warning being written to the log Could not load file or assembly 'My.Service.API, Version=2018.3.5.20551, Culture=neutral, PublicKeyToken=null' or one of its dependencies. which is perfectly understandable as it doesn’t have the dll… But I dont want the HF1 instance to bother with HF2’s queues and jobs and vice versa, how do I configure them to only care about their own queues and jobs?


#2

It’s hard from the information to be sure what the root cause is.

You are sharing the same repository tables. You could use the storage options to change the Prefix use by both instances. This has the effect that API1 (and all related stuff) would use a different set of tables for each. This is a storage option, so it might not be possible with all storage implementations. I only use the MongoStorage myself and it has this option.

You look to have done all the settings needed otherwise so not sure why it is getting the queues mixed up really.

The only little twinkle of doubt about your code I have is that you have a variable in the [Queue(…)] attribute. This would only work if that variable (HangfireConfig.QueueName) is a Const.


#3

Yes it is a const

[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(HangfireConfig), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethod(typeof(HangfireConfig), "Shutdown")]

public class HangfireConfig
{
    private static BackgroundJobServer backgroundJobServer;
    public const string QueueName = "Q1";

    public static void Start()
    {
        GlobalConfiguration.Configuration.UseSqlServerStorage(ConfigurationManager.ConnectionStrings["ConnectionString.Db.Hangfire"].ConnectionString);
        GlobalConfiguration.Configuration.UseActivator(new ContainerJobActivator(UnityConfig.GetConfiguredContainer().CreateChildContainer()));
        
        JobHelper.SetSerializerSettings(new JsonSerializerSettings
        {
            ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
            DateTimeZoneHandling = DateTimeZoneHandling.Utc
        });

        RecurringJob.AddOrUpdate<IService>("J1", s => s.DoJob(), Cron.Weekly(DayOfWeek.Monday, 01), TimeZoneInfo.Local, QueueName);

        backgroundJobServer = new BackgroundJobServer(new BackgroundJobServerOptions
        {
            Queues = new [] { QueueName }
        });
    }

    public static void Shutdown()
    {
        backgroundJobServer?.Dispose();
    }
}

#4

I decided to go with the database schema approach, which worked wonders, thank you :slight_smile: @Hans_Engelen


#5

Good to hear.

Happy coding!