BlogExamples icon indicating copy to clipboard operation
BlogExamples copied to clipboard

Cron - Not running multiple instances of a job

Open y2k4life opened this issue 1 year ago • 2 comments

This is not an elaborate solution, but it works (in theory). You can't choose to have multiple instances running or not. I just assumed not to have multiple instances running regardless. I assumed this is not required unless you are running a job every minute or two.

I added a field to the scheduler that tracks the Task returned by job.Run(stoppingToken);. On ever tick check the list for completed tasks and clear them. Prior to running a job skip if it is on the list of running jobs.

I'm sure this might need some tweaking this was my first attempt at it.

private Dictionary<string, Task> _runningJobs;

.
.
.

// Clear completed jobs
foreach (var key in _runningJobs.Keys)
{
    if (_runningJobs[key].IsCompleted)
    {
        _runningJobs[key].Dispose();
        _runningJobs.Remove(key);
    }
}

// Run jobs that are in the map
RunActiveJobs(runMap, now, stoppingToken);

.
.
.

foreach (var run in currentRuns)
{

    // We are sure (thanks to our extension method)
    // that the service is of type ICronJob
    var job = (ICronJob)_serviceProvider.GetRequiredService(run);
    string jobName = job.GetType().Name;

    // Continue to next job if job is already running
    if (_runningJobs.ContainsKey(jobName))
    {
        continue;
    }

    // We don't want to await jobs explicitly because that
    // could interfere with other job runs
    var task = job.Run(stoppingToken);

    // Add task to running jobs
    _runningJobs.Add(jobName, task);
}

y2k4life avatar Mar 22 '23 00:03 y2k4life

I don't even think that the solution is "not an elaborate" as you put it. I would do the same and track the running tasks, which gives you the flexibility to:

  • Have only one task running
  • Or have n tasks running
  • Implement behavior like: "If I start a new task, the old should be cancelled"

I guess I would refactor this into its own class, but the underlying idea would be the same. Small nitpick: You don't have to Dispose tasks in general (99% of cases). There is a nice article from Stephan Toub: https://devblogs.microsoft.com/pfxteam/do-i-need-to-dispose-of-tasks/

linkdotnet avatar Mar 22 '23 07:03 linkdotnet

I was wondering about the disposeing of a task, I backed that out. The additional features sound great and I would assume would be set when registering the job. Not only when to run the task, but how many.

y2k4life avatar Mar 22 '23 16:03 y2k4life