HomeDev GuideAPI Reference
Dev GuideAPI ReferenceUser GuideGitHubNuGetDev CommunitySubmit a ticketLog In
GitHubNuGetDev CommunitySubmit a ticket

Scheduled jobs

Describes scheduled jobs in Optimizely Content Management System (CMS) versions 10 and 11 that run in the background at preset time intervals and typically perform cleanup and updating tasks.

A sample installation of Optimizely Content Management System (CMS) has several predefined scheduled jobs that are administered in the admin view. You can customize and configure scheduled jobs and create your own.

During the initialization of CMS, the system scans through jobs and checks for their next execution time. At the appointed time, the system executes the job. Alternatively, you can execute a job manually from admin view. Scheduled jobs are executed in an Anonymous context. Because scheduled jobs are executed in the same process as the site, the site's web server must be up and running. To ensure this, use the IIS feature Application Initialization, or have a site supervisor periodically ping the site. In Azure Web Apps, enable Always On.

Built-in scheduled jobs

A standard CMS installation comes with a set of built-in scheduled jobs, such as emptying the trash and managing the scheduled publishing of content. These jobs are available from the CMS administration view.

Implement a scheduled job

Scheduled jobs can be easily created using the Optimizely Visual Studio extension. To implement a scheduled job, create a class that inherits from the EPiServer.Scheduler.ScheduledJobBase base class. Decorate the class with the ScheduledPlugInAttribute and define if the job should be enabled and what interval should be used initially. You can also assign a GUID to your job, making it possible to change the name or namespace of the job at a later time [New in CMS Core 10.3.0]. You also can use a class that does not inherit the base class. Such a scheduled job is required to have a static method named Execute that does not take any arguments and that returns a string. You can also injected all dependencies from the constructor.

Example: A basic scheduled with the possibility to stop a job by overriding Stop method, as well as the ability to report progress through the StatusChanged event.

using System;
using EPiServer.Core;
using EPiServer.PlugIn;
using EPiServer.Scheduler;

namespace MyEpiserverSite.Jobs
{
    [ScheduledPlugIn(DisplayName = "ScheduledJobExample", GUID = "d6619008-3e76-4886-b3c7-9a025a0c2603")]
    public class ScheduledJobExample : ScheduledJobBase
    {
        private bool _stopSignaled;

        public ScheduledJobExample()
        {
            IsStoppable = true;
        }

        /// <summary>
        /// Called when a user clicks on Stop for a manually started job, or when ASP.NET shuts down.
        /// </summary>
        public override void Stop()
        {
            _stopSignaled = true;
        }

        /// <summary>
        /// Called when a scheduled job executes
        /// </summary>
        /// <returns>A status message to be stored in the database log and visible from admin mode</returns>
        public override string Execute()
        {
            //Call OnStatusChanged to periodically notify progress of job for manually started jobs
            OnStatusChanged(String.Format("Starting execution of {0}", this.GetType()));

            //Add implementation

            //For long running jobs periodically check if stop is signaled and if so stop execution
            if (_stopSignaled)
            {
                return "Stop of job was called";
            }

            return "Change to message that describes outcome of execution";
        }
    }
}

The example scheduled job as it appears in the admin view:

Multi-server scenario

If several IIS sites share a database, such as in a load-balanced scenario, you can control which IIS site executes scheduled jobs. To do this, set the enableScheduler attribute to true on the applicationSettings configuration element on the site that should execute the jobs, and to false on the other sites.

📘

Note

Running the job manually ignores the enableScheduler setting and runs the job on the particular server or instance.

If you configure several IIS sites to run scheduled jobs, each job is scheduled for execution on all sites. However, during execution, the first site that starts executing a job marks it in the database as executing, so the other sites do not execute that job in parallel.

Restartable jobs

📘

New in CMS Core 10.8

If the IIS crashes or is recycled when a job is running, the scheduler runs the job on the next scheduled time by default. A restartable job is started again to make sure it can run to completion. The job can restart on any available server.

Set the Restartable property on the ScheduledPlugIn attribute. The job should also be implemented in such a way that it can be started repeatedly. For example, if the job processes data, it should be able to continue where it was aborted. It is also recommended to implement a stoppable job, but be aware that the Stop method is only called for controlled shutdowns which can be picked up by ASP.NET, and not for uncontrolled shutdowns such as an IIS crash or other external changes.

[ScheduledPlugIn(Restartable = true)]

In the unlikely event the job is repeatedly cancelled, or the job itself is causing the shutdowns, there are a maximum number of 10 start attempts per job. When that limit has been reached, the job will run on the next scheduled time.

Custom content cache expiration

📘

New in CMS Core 11.1

Content loaded from database and added to cache by scheduled jobs have a shorter cache expiration (default 1 minute), both since it is unlikely that the content will be used again and to keep down memory usage of long running jobs.

You can customize the expiration that is being set on content loaded from the database using the ContentCacheScope class.

var repo = ServiceLocator.Current.GetInstance<IContentRepository>();
    using(var x = new ContentCacheScope { SlidingExpiration = TimeSpan.FromMinutes(10) })
    {
       var content = repo.Get(contentLink)
       //etc..
    }