Scheduling

Any time, any place, any where.

Introduction

Scheduling in Oddjob is provided by a scheduler job. The scheduler job supports three types of scheduling instruction:

Schedule Instructions are instructions to the scheduler to schedule something. As such they are fairly dumb containers for properties. The schedule will create a Schedule Handler to deal with the act of scheduling. The schedule handler is that node that you see under a sheduler in Oddjob Explorer. Schedule Handler have different properties to Schedule Instructions, some of which can be set at runtime. The subtle difference between the two can be confusing at first, but becomes obvious with use.

The Oddjob Schedule Instruction is by far the most powerful. Oddjob can schedule a job to run at certain times, on certain days, in certain months etc etc. Here's an example:

<oddjob>
  <sequential>
    <scheduler name="This is the scheduler">
      <schedules>
        <ojschedule id="morning" name="This is one schedule" job="${morning-job}">
          <schedule>
            <time to="11:59">
              <interval interval="00:15"/>
            </time>
          </schedule>
        </ojschedule>
        <ojschedule id="afternoon" name="This is another schedule" job="${afternoon-job}">
          <schedule>
            <time from="12:00">
              <interval interval="00:15"/>
            </time>
          </schedule>
        </ojschedule>
      </schedules>
    </scheduler>
    <folder name="My Jobs">
        <echo id="morning-job" name="Morning Job" text="Good Morning."/>
        <echo id="afternoon-job" name="Afternoon Job" text="Good Afternoon."/>
    </folder>  
  </sequential>
</oddjob>

Retry Schedules

The ojschedule Schedule Instruction can be provided with a retry schedule. If the job being scheduled fails or throws an exception Then the retry schedule will be invoked. Here' an example:

<oddjob>
  <sequential>
    <scheduler name="This is the scheduler">
      <schedules>
        <ojschedule id="daily" name="Daily Schedule" job="${a-job}">
          <schedule>
            <time from="07:00/">
          </schedule>
          <retry>
            <time to="14:00">
              <interval interval="00:15"/>
            </time>
          </retry>
        </ojschedule>
      </schedules>
    </scheduler>
    <folder name="My Jobs">
        <class class="org.oddjob.devguide.NaughtyJob" id="a-job"/>
    </folder>  
  </sequential>
</oddjob>

In this example the retry schedule will keep trying the job every 15 minutes until 2pm. When the schedule is retrying the Schedule handler will be in a not complete state. when the retry schedule completes, at 2pm, the schedule handler will be in an exception state and the schedule will revert back to the normal schedule so it will be next due at 7am the next day.

The retry schedule is constrained by the main schedule, if we'd excluded the time constraint the retry schedule would have continued until midnight.

It's possible to use a trigger schedule to fire an alert when the handler switches to the exception state. It's better that this happens at 2pm rather than midnight so adding the additional constraint to the retry makes sense.

The schedule type

Both the schedule and retry properties of an ojschedule are of schedule types. These types can not only be defined as part of the ojschedule configuration, but can be defined as properties of the variables job allowing things such as holidays or a global retry policy to be defined and shared between scheduled jobs. Understanding the schedule type is the key to understanding how to schedule with Oddjob.

A schedule definition is defined as hierarchy of sub-schedules, each providing a tighter constraint on the time frame of the schedule - from yearly events down to the millisecond.

Most of the time a hierarchy will be very simple, such as:

<schedule>
  <dayofweek on="mon">
    <time on="08:00"/>
  </dayofweek>
</schedule>

This would schedule a job at 8am every Monday. There is no limit to how complicated the hierarchy can become.

<schedule>
  <dayofweek on="mon">
    <time on="08:00"/>
  </dayofweek>
  <dayofweek from="tue" to="sun">
    <time on="09:00"/>
    <time on="15:00"/>
  </dayofweek>
</schedule>

This would schedule a job at 8am every Monday, then at 9am and 3pm every other day.

When a schedule is evaluated each schedule in the list is evaluated and the first due schedule is used as the next due date.

The list of sub schedules can be quite unrelated.

		
<schedule>
  <dayofweek on="wed">
    <time on="12:00"/>
  </dayofweek>
  <dayofmonth on="5">
  <time on="14:00"/>
</schedule>

Hopefully you're beginning to get the idea...

To provide the constraints for a possible sub schedule, a schedule always returns an interval - a from and a to date. At the top level this could be considered irrelevant because you want your schedule to begin at a certain time so you will probably use on="12:00" property of the time schedule which returns the 1 millisecond wide interval from 12:00:00:000 to 12:00:00:001. However this side affect of using an interval is put to good use in the ojscehdule schedule instruction as it allows for a late starting server which is something you may wish to consider when defining schedules.

Advanced Scheduling

Holidays can be accounted for using the broken schedule. Here's an example.

<oddjob>
  <sequential>
    <variables id="global" name="Globally Shared Definitions"> 
      <schedule name="uk-holidays">
        <date on="27-DEC-04"/>
        <date on="28-DEC-04"/>
        <date on="03-JAN-05"/>
        <date on="25-MAR-05"/>
        <date on="28-MAR-05"/>
        <date on="02-MAY-05"/>
        <date on="30-MAY-05"/>
        <date on="29-AUG-05"/>
        <date on="26-DEC-05"/>
        <date on="27-DEC-05"/>
      </schedule>
    </variables>
    <scheduler name="Scheduler">
      <schedules>
        <ojschedule id="daily" name="Daily Schedule" job="${a-job}">
          <schedule>
            <broken breaks="${global.uk-holidays}">
              <schedule>
                <time from="07:00"/>
              </schedule>
            </broken>
          </schedule>
        </ojschedule>
      </schedules>
    </scheduler>
    <folder name="My Jobs">
        <echo text="Work Work Work!" id="a-job"/>
    </folder>  
  </sequential>
</oddjob>

Last days of the month can achieved easily using the <dayofmonth on="0"> schedule. The last working day of the month is a bit harder, but can be achieved using the last schedule. The last schedule takes the last result of its sub schedules, so it calculates the month end by moving through all the days before the month end and seeing if it's a working day or not.

Here's an example that will run the job a 10pm on the last working day of every month.

<oddjob>
  <sequential>
    <scheduler name="Scheduler">
      <schedules>
        <ojschedule id="last" name="Last Day of the Month" job="${a-job}">
          <schedule>
            <dayofmonth from="-5">
              <last>
                <broken>
                  <schedule>
                     <time from="22:00" />
                  </schedule>
                  <breaks>
                    <dayofweek on="SAT" />
                    <dayofweek on="SUN" />
                    <date on="27-DEC-04" />
                    <date on="28-DEC-04" />
                    <date on="03-JAN-05" />
                    <date on="25-MAR-05" />
                    <date on="28-MAR-05" />
                    <date on="02-MAY-05" />
                    <date on="30-MAY-05" />
                    <date on="29-AUG-05" />
                    <date on="26-DEC-05" />
                    <date on="27-DEC-05" />
                  </breaks>
              </broken>
            </last>
          </dayofmonth>
          </schedule>
        </ojschedule>
      </schedules>
    </scheduler>
    <folder name="My Jobs">
        <echo text="Work Work Work!" id="a-job"/>
    </folder>  
  </sequential>
</oddjob>          

If you run this in oddjob - try setting the reSchedule property to see the affect in different months.

Time Zones

The ojschedule can be given a time zone. If this is the case, the schedule will be evaluated in that time zone, regardless of the time on the server.

Time zones can be particularly useful when scheduling a download with a server in a different geographical location. By using their time zone the schedule will automatically account for their daylight saving time and will schedule holidays that span their day not your local day.

Time zones can also be useful when using a server in a different region as the backup server. By using time zones for schedules it's possible to stop your local server, copy all your configuration files to the backup server and start up Oddjob with no impact on scheduled times.

Daylight Saving Time

The ojschedule will always use the given time zone, or default time zone for the machine, to provide the daylight saving time information. To schedule without daylight saving time use a time zone that is fixed such as 'GMT+08'.

The Other Schedule Instructions

The cron schedule is straightforward for those used to cron expressions. Please see the reference for more information.

The trigger is a schedule that is job, rather than time, dependent. The trigger schedule will run a job when a second job enters a specified state. Triggers are particularly useful for firing alerts.

A trigger schedule can also be used in conjunction with a sequential job and a trigger job to provide a schedule that fires only when several jobs have completed.

The trigger schedule is relatively easy to configure. Please see the reference documentation for more information.

Scheduling with Dependencies

The natural cascading nature of job execution through the use of sequential and parallel jobs means that dependencies within scheduling aren't required as often as they would in other scheduling systems.

Although scheduling on completion of a job is possible with the trigger schedule, there is no retry option on a trigger schedule at the moment witch could be required for the sequence being scheduled. The way to get round this is to use one schedule to schedule another.

<oddjob id="this">
  <sequential>
    <scheduler name="Scheduler" id="scheduler">
      <schedules>
        <trigger id="wait" name="Wait Job" on="${other-job}" job="${depends}"/>
      </schedules>
    </scheduler>
    <folder name="My Jobs">
      <sequential id="a-sequence">
        <exists file="${this-dir}/*.xml"/>
        <echo text="Finally I get to do some work." id="a-job"/>
      </sequential>
      <echo id="other-job" text="I'm done" name="Run Manually"/>
      <schedule scheduler="${scheduler}">
        <schedules>
          <ojschedule id="depends" name="Depends on some things" job="${a-sequence}">
            <schedule>
              <time from="22:00" to="06:00"/>
            </schedule>
            <retry>
              <interval interval="00:05"/>
            </retry>
          </ojschedule>
        </schedules>
      </schedule>
    </folder>  
  </sequential>
</oddjob>

Ok - it's a bit messy - but it show's what's possible.

Inside Scheduling

Internally Oddjob uses a package called Quartz to provide scheduling capabilities. For more information please see the Quartz Website.


Index Top Next