Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get List of all Hangfire Jobs using JobStorage in C#?

I am using Hangfire BackgroundJob to create a background job in C# using below code.

var options = new BackgroundJobServerOptions
        {
            ServerName = "Test Server",
            SchedulePollingInterval = TimeSpan.FromSeconds(30),
            Queues = new[] { "critical", "default", "low" },
            Activator = new AutofacJobActivator(container),
        };
        var jobStorage = new MongoStorage("mongodb://localhost:*****", "TestDB", new MongoStorageOptions()
        {
            QueuePollInterval = TimeSpan.FromSeconds(30)                
        });
        var _Server = new BackgroundJobServer(options, jobStorage);

It creates Jobserver object and after that, I am creating Schedule, Recurring Jobs as below.

var InitJob = BackgroundJob.Schedule<TestInitializationJob>(job => job.Execute(), TimeSpan.FromSeconds(5));
        var secondJob = BackgroundJob.ContinueWith<Test_SecondJob>(InitJob, job => job.Execute());
        BackgroundJob.ContinueWith<Third_Job>(secondJob, job => job.Execute());
        RecurringJob.AddOrUpdate<RecurringJobInit>("test-recurring-job", job => job.Execute(), Cron.MinuteInterval(1));

After that, I want to delete or stop all Jobs when my application is stop or close. So in OnStop event of my application, I have written below code.

var monitoringApi = JobStorage.Current.GetMonitoringApi();
                    var queues = monitoringApi.Queues();// BUT this is not returning all queues and all jobs
                    foreach (QueueWithTopEnqueuedJobsDto queue in queues)
                    {
                        var jobList  = monitoringApi.EnqueuedJobs(queue.Name, 0, 100);
                        foreach (var item in jobList)
                        {
                            BackgroundJob.Delete(item.Key);
                        }
                    }

But, the above code to get all the Jobs and all Queues is not working. It always returning "default" queue and not returning all jobs.

Can anyone have an idea to get all the Jobs using Hangfire JobStorage and Stops those job when Application is stopped?

Any Help would be highly appreciated!

Thanks

like image 446
prog1011 Avatar asked Nov 16 '22 17:11

prog1011


1 Answers

Single Server Setup

To get all recurring jobs you can use the job storage (e.g. either via static instance or DI):

using (var connection = JobStorage.Current.GetConnection())
{
  var recurringJobs = connection.GetRecurringJobs();
  foreach (var recurringJob in recurringJobs)
  {
    if (NonRemovableJobs.ContainsKey(recurringJob.Id)) continue;
    logger.LogWarning($"Removing job with id [{recurringJob.Id}]");
    jobManager.RemoveIfExists(recurringJob.Id);
  }
}

If your application acts as single Hangfire server, all job processing will be stopped, as soon as the application is stopped. In this case they wouldn't even need to be removed.

Multi Server Setup

In a multi instance setup which uses the same Hangfire tables for multiple servers, you'll run into the problem that not all applications have all assemblies available. With the method above Hangfire tries to deserialize every job it finds, which results in "Assembly Not Found" exceptions.

To prevent this I used the following workaround, which loads the column 'Key' from the table 'Hash'. It comes in the format 'recurring-jobs:{YourJobIdentifier}'. Then the job id is used to remove the job if neccessary:

var queue = 'MyInstanceQueue'; // probably using queues in a multi server setup
var recurringJobsRaw = await dbContext.HangfireHashes.FromSqlInterpolated($"SELECT [Key] FROM [Hangfire].[Hash] where Field='Queue' AND Value='{queue}'").ToListAsync();
var recJobIds = recurringJobsRaw.Select(s => s.Key.Split(":").Last());
foreach (var id in recJobIds)
{
  if (NonRemovableJobs.ContainsKey(id)) continue;
  logger.LogWarning($"Removing job with id [{id}]");
  jobManager.RemoveIfExists(id);
}

P.S.: To make it work with EF Core I used a Keyless entity for the Hangfire.Hash table.

like image 141
Radall Avatar answered Feb 06 '23 07:02

Radall