How do i cancel an already runnign recurring job?

Hello to everyone,

I’m currently using hangfire on my web application to schedule recurring jobs the following way

from controller i recive all that i need to build a cron expression and tell hangfire wich method from a service called hangFireServices i want to execute
(my jobs are stored on the database and not the startup.cs file)

_recurringJobManager.AddOrUpdate(id, () => _hangFireServices.methodName(), cron);

my method is very simple it just move files from one origin folder to another storage, one file at the time, why one at the time and not all at once? well for each file i have to do more stuff but it is not important what. Problem is that the amount of files is too large and thus the job takes too long and the job it is usually configured to execute every hour. the situation is this:

  1. the firs execution of my job starts at 8 am
  2. it’s 9am therefore is time for a new execution but first execution has not finished.
  3. before starting the new executed which cannot be posponed i need to stop the first execution this without deleting the job because it still needs to execute every hour

also, end user wants to be able to stop the execution by pressing a button or something like that.

is there a way of doing this? some post mentioned the use of cancellation token but i don’t know how to trigger this for jobs that are already running.

please help.

1 Like

I am assuming you are looping through a list of files inside your job. One possibility would be to start a Stopwatch when you begin, and check it before each iteration of your loop. Once the total duration exceeds a threshold you set (e.g. 55 minutes) then you exit the loop. The job then completes, although it has not finished processing all the available data. Your next job triggered by the recurring job will pickup where the last one left off.

You would use a similar method if you’d like to stop the job prematurely via user interaction. When the user requests it to stop, you set a value in your database (or wherever you want to store the Stop Request). Each iteration of your job would check that value, and if it indicates a Stop Request, then exit the loop.

You can achieve this by using IMonitorinApi and fetch jobs that are processing. Then you can delete them by using IBackgroundJobClient. You need to pass in a cancellationtoken though.

    public void InitializeJobs()
    {
        const string myRecurringJobId = "Ftmch-20";
        _recurringJobManager.AddOrUpdate(
            myRecurringJobId,
            Job.FromExpression<MyJob>(j => j.LongRunningJob(null, CancellationToken.None)),
            "0/10 * * * * *");
    }

    public class MyJob
    {
        private readonly IBackgroundJobClient _backgroundJobClient;

        public MyJob(IBackgroundJobClient backgroundJobClient) => _backgroundJobClient = backgroundJobClient;

        public void LongRunningJob(PerformContext context, CancellationToken cancellationToken)
        {
            var currentJobId = context.BackgroundJob.Id;

            var monitoringApi = JobStorage.Current.GetMonitoringApi();

            var jobsToDelete = monitoringApi.ProcessingJobs(0, 1000)
                .Where(j => j.Value.Job.Type == typeof(MyJob))
                .Where(j => j.Key != currentJobId)
                .ToList();

            foreach (var jobToDelete in jobsToDelete)
            {
                _backgroundJobClient.Delete(jobToDelete.Key);
            }

            var endTime = DateTime.UtcNow.AddMinutes(5);
            while (endTime > DateTime.UtcNow)
            {
                cancellationToken.ThrowIfCancellationRequested();
                Thread.Sleep(2000);
            }
        }
    }