Monday, April 21, 2008

Adding Custom Scheduled Agents

After you get yourself familiar with the logic of Sitecore Scheduler, you may be interested in creating your own custom scheduled agent.

There are two ways of doing that. The most elegant way is to create a "task" and a "schedule" item under the "/sitecore/system/Tasks" in the master database as described in this article. After you create a command referencing a class that you develop and a schedule item to set the timing parameters, the out-of-the-box DatabaseAgent will pick it up on the scheduled basis according to its interval parameter (remember the loop nature of things). By default, there are two DatabaseAgents defined in the system. One is for the "master" database, another for "core". This should be kept in mind since in the staged environments when the content delivery server does not have access to neither core nor master database, you may need to adjust it and change the "database" parameter to "web" as your schedule item definitions should be published anyway.

There is another way to approach the creation of the custom scheduled agents and you may already guessed it. You can simply develop an agent class (see below), compile it and provide the definition of your custom agent to the Sitecore Scheduler by defining it in the web.config:

   1: <scheduling>
   2:   <frequency>00:00:10</frequency>
   3:   <!-- default agents go here... -->
   4:   <agent type="MyProj.MyAgent, MyDLL" method="Run" interval="00:10:00">
   5:     <param desc="myparam">valueofmyparam</param>
   6:   </agent>
   7: </scheduling>

The reference in the "type" attribute should correspond the existing class within existing assembly in the "bin" directory as usual.

The skeleton of any custom agent is shown below. You can dynamically pass different string parameters to your agent:

   1: public class MyAgent
   2: {
   3:     // one string parameter that can be passed from the web.config definition
   4:     private string myparam;
   6:     // Constructor
   7:     // Notice that it expects the parameter from the agent definition
   8:     public MyAgent(string myparam)
   9:     {
  10:         this.myparam = myparam;
  11:     }
  13:     // A method that is dynamically executed by Sitecore Scheduler
  14:     public void Run()
  15:     {
  16:         // do your processing here
  17:     }
  18: }

Enjoy responsibly.

Sitecore Scheduling Explained

Sitecore provides a framework for the process scheduling out of the box. This functionality is often used in the scenarios when it is important to automate a background process of any sort such as content sync or import, cleanup, etc. So it is critical to understand the underlying logic of this process which is really straightforward, but may be unknown for the newbies.

The Sitecore Scheduler is basically a background process that is started with the sleep interval defined in the <frequency> section.
The skeleton of the <scheduling> section looks like this:

   1: <scheduling>
   2:  <frequency>00:10:00</frequency>
   3:  <agent ...>
   4:  </agent>
   5: </scheduling>

Within the execution of the Scheduler, it queries the inner contents for the agents defined there and adds to the queue only those agents which marked as "due". An agent is considered "due"  if the value of the "interval" parameter is less than the timeframe of the last execution. In other words, if the agent was run 4 minutes ago last time (the frequency is set to 1 minute for example) and the interval parameter of the agent is 5 minutes, it is obvious that it will not run this time. So you may find it convenient to think about the global frequency parameters as an external loop.

An agent is considered disabled if the "interval" parameter is set to zero seconds ("00:00:00").

After the logic is able to retrieve a list of agents marked as "due", each agent is executed as a job process and the last run date is updated.

Here are some examples of what is expected in two different configurations below:

1. The case when "MyAgent" will not be executed each 10 seconds due to the bigger value in the "frequency" parameter. The agent will still be executed each 10 minutes. This is a common configuration issue for the Staging module.

   1: <scheduling>
   2:   <frequency>00:10:00</frequency>
   3:   <agent type="MyProj.MyAgent, MyDLL" method="Run" interval="00:00:10"/>
   4: </scheduling>

2. In this case the MyAgent code will be executed roughly each 10 minutes as specified in "interval" but will be triggered for the "IsDue" check each 10 seconds:

   1: <scheduling>
   2:   <frequency>00:00:10</frequency>
   3:   <agent type="MyProj.MyAgent, MyDLL" method="Run" interval="00:10:00"/>
   4: </scheduling>

Hope this makes sense.