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

1

6

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

Brott answered 11/1, 2019 at 6:44 Comment(2)
Have you tried getting your jobs like this: monitoringApi.ScheduledJobs(0, 100)? For me that solved the problem.Hamrah
Why would you want to stop the jobs at app termination? Maybe to avoid inconsistent states? If so, please fix the job code to handle this, because non-graceful app terminations may occur at anytime.Queasy
E
4

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.

Eserine answered 17/8, 2021 at 6:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.