EPiServer: working with Scheduled Jobs programmatically. Revisited.

A few years ago I wrote an article on how to work with Episerver scheduled jobs programmatically. Since then Episerver has improved the API.

In the latest version, you still have a repository. However, instead of using a class, you should ask for an interface - IScheduledJobRepository. It still has the same set of methods:

  • Get(Guid id):ScheduledJob
  • Get(string method, string typeName, string assemblyName):ScheduledJob
  • List():IEnumerable
  • Save(ScheduledJob job):void

See my previous article for detailed information.

The main changes in the API are about executing these jobs. Stop, ExecuteManually and other methods of a ScheduledJob class now are obsolete. You should use IScheduledJobExecutor instead. IScheduledJobExecutor has three methods:

  • StartAsync(ScheduledJob job, JobExecutionOptions options, CancellationToken cancellationToken):Task - starts a job with provided options and cancellation token,
  • Cancel(Guid id):void - cancels a job by Id,
  • ListRunningJobs():IEnumerable - - returns a list of running jobs.

IScheduledJobExecutor also has several extension methods. These extension methods make it much easier to work with scheduled jobs:

  • StartAsync(this IScheduledJobExecutor executor, ScheduledJob job):Task - starts a job without any parameters,
  • StartAsync(this IScheduledJobExecutor executor, ScheduledJob job, JobExecutionOptions options):Task - starts a job with options,
  • ListRunningJobs<T>(this IScheduledJobExecutor executor):IEnumerable<T> - lists jobs of a specific type.

So with all this in your tool belt, you can load a job by id and start it.

public async RunMyJob()
    var job = _scheduledJobRepository.Get(new Guid(MyJob.Guid));
    if (job.IsRunning)

    var result = await _scheduledJobExecutor.StartAsync(job);
    if (result.Status == ScheduledJobExecutionStatus.Succeeded)

    Log.Error($"Failed to start a job: {result.Status} {result.Message}");

You also, can pass some options:

await _scheduledJobExecutor.StartAsync(job, new JobExecutionOptions
    Trigger = ScheduledJobTrigger.User,
    RunSynchronously = true,
    ContentCacheSlidingExpiration = null

Here the trigger just indicates how this job was started. It has four values - Unknown, Scheduler, User, Restart. So you can fake how it was started :)

RunSynchronously set to true will run the job synchronously.

With ContentCacheSlidingExpiration you can set how long content is cached when executed.