Episerver/Optimizely Scheduled jobs - always add a GUID!

Creating a scheduled job

A scheduled job is Episerver's/Optimizely's way of running some piece of code at a configurable interval. In order to create a scheduled job, create a class and decorate it with the [ScheduledPlugIn] attribute and (optionally) inherit the EPiServer.Scheduler.ScheduledJobBase base class.

How Episerver/Optimizely keeps track

When an Episerver/Optimizely site starts, all classes with the [ScheduledPlugIn] attribute are scanned, and the database table tblScheduledItem is updated if needed.

Since Episerver.CMS.Core 10.3.0 released December 27th 2016, it has been possible to add a GUID attribude to the [ScheduledPlugIn] attribute.

  • If the attribute contains a GUID, and the GUID does not exist in the database table, a new row is added.
  • If the attribute does not contain a GUID, the fully qualified name (namespace + class name) is checked against the TypeName column in the tblScheduledItem table.

When the scheduler runs, the column NextExec in the same table is checked and the TypeName column is used to instantiate the specific scheduled job class. If the TypeName does not exist in your solution, the code can not run and an error will be logged.

Renaming a scheduled job class

If you change a scheduled job's fully qualified name, i.e. change the namespace or class name, the row in the table tblScheduledItem is duplicated. The duplication will also create orphan rows in both the table tblScheduledItem and tblScheduledItemLog, and you will also lose the job history in the GUI.

However, if you have added a GUID to your [ScheduledPlugIn] attribute, the correct row is updated, and not duplicated. I recommend adding the GUID when you initially create the scheduled job. Example.

namespace MyOptimizelySite.Jobs
{
   [ScheduledPlugIn(DisplayName = "Example", GUID = "5FB26B93-3CDF-40E9-A89D-CCD7F3E38353")]
   public class ExampleJob : ScheduledJobBase
   {
      ...
      ...
   }
}

If you did not add the GUID before running your code for the first time, you will have to add the GUID created by Episerver/Optimizely to your attribute.

In order to get the GUID for the above example job, run the query below. I recommend looking at the TypeName, as the Name of the job is not updated if changed in code.

SELECT pkID
FROM tblScheduledItem
WHERE TypeName = 'MyOptimizelySite.Jobs.ExampleJob'

Then add the pkID to the attribute using the GUID parameter.

If you already have an orphan row in tblScheduledItem, you can remove it. Remember to delete any log entries first, like this.

DECLARE @id AS uniqueidentifier = '5FB26B93-3CDF-40E9-A89D-CCD7F3E38353'

DELETE FROM tblScheduledItemLog
WHERE fkScheduledItemId = @id

DELETE FROM tblScheduledItem
WHERE pkID = @id

Conclusion: Always add a GUID when creating a scheduled job!

That's all!