X

News, tips, partners, and perspectives for the Oracle Solaris operating system

  • July 30, 2015

Creating Scheduled Services in Oracle Solaris

In the previous post, we introduced the idea of scheduled services in Oracle Solaris as an alternative to cronjobs.  Here, we'll do a deep dive into the scheduling model and create a basic service.

Scheduling Model

Scheduled Services and cronjobs have fundamentally different scheduling models.  The model that cron(1M) uses is based on pattern matching. Each line in a crontab specifies a set of conditions specifying when a job should run. Each minute, the cron daemon wakes up and checks each job to see if those criteria match the current moment.  If they do, then cron executes the job.


Scheduled Services, on the other hand, use an interval and frequency based model similar to iCalendar. Rather than saying that a job should run on each day that matches a given weekday a la cron, scheduled services are told to run 'weekly'. The interval is a property in the schedule and can have one of the following values: year, month, week, day, hour, minute. If the interval is 'year', the service executes once a year. If it's 'day', the services is executed each day. From there, the schedule can be further specified by adding additional properties know as constraints.Constraints for a given interval can be defined starting from the next smallest unit of time. For a weekly interval, the biggest constraint that can be specified is the day of the week. If more control is required, constraints run all the way down to the minute. Again for a weekly interval, the allowable constraints are day, hour, and minute. For a daily schedule, only hour and minute are allowed. One caveat is that constraints must be contiguous, meaning gaps are not allowed. A weekly interval can have day and hour, for example, but not day and minute. This is because the hour is missing. Any value that is not constrained is randomized by the periodic restarter. To make sure Dumb Things don't happen, the periodic restarter only randomizes the first unconstrained unit once. That way something that executes once a year won't run on December 31st of one year and January 1st of the next. It will run in the same month every time.


The periodic restarter supports three different calendar models for scheduled services. One of them uses the Gregorian model where dates are specified by the year, the month, and the day of the month. February 8th, 1976, for example. Another is the ISO Week Date format. This method defines a date using the year, the number of weeks into that year, and a day of the week. This results in dates such as Tuesday, in the 34th week of 2027. Finally, there is a model that arose out of the need to cleanly represent holidays in the United States. Instead of specifying a day of a month, the model supports specifying a day of the week along with which instance of that day in a given month. For example, the 4th Thursday in November.


Here is the full set of constraints allowed for each schedule type:


Gregorian Dates:

year

month

day_of_month

hour

minute

ISO Week Dates:

year

week_of_year

day

hour

minute


Month-Week Dates:

year

month

weekday_of_month

day

hour

minute


Most schedules can be adequately defined using a combination of intervals and constraints. But what if you need to execute your service, say, every 2 weeks? To handle this, scheduled services also have a frequency property. The frequency defines how many intervals must pass before the service executes again. To create a scheduled service that runs every two weeks, set the interval to 'week' and the frequency to '2'.


Schedules that have a frequency other than 1 need to define where to start counting. If your service should run every two years, the periodic restarter needs to know if it should be running in even years or odd years. This is known as a reference point. A reference point is defined using the same properties as constraints. The difference is that constraints start at the next shortest unit of time, whereas reference points always start with a year and end with the same unit of time. For the 2 week case, it is necessary to specify at least enough information to determine a specific week of a specific year.  It doesn't matter which of the 3 scheduling models is used, so long as there is enough information to know from what week to start counting.  It should be noted that reference points are not the same thing as a starting date, and is used only for determing when to schedule an execution. A service that runs every 5 years with a reference point of 2050 will run in 2015, 2020, 2025, and so on.  Scheduled Services do not have a notion of a start nor end date and will run both before and after the reference point.


So know what we know what constitutes a schedule, how do we make one? Each service delegated to the periodic restarter can have an arbitrary number of schedules, each in its own property group with type 'schedule'. All properties are optional except the 'interval' property. The periodic restarter then combines all the schedules and computes when the service should next be executed.

Creating a Scheduled Service

The vast majority of scheduled services are going to have a single schedule. To make that use case easier, we've added a new element to the service bundle DTD, 'scheduled_method'. This element does three things. It creates a schedule property group, creates a start method, and also delegates the instance to the periodic restarter. A manifest for a simple scheduled services looks like:


<?xml version="1.0" ?>

<!DOCTYPE service_bundle

SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'>

<service_bundle type="manifest" name="example/scheduled">

<service version="1" type="service" name="example/scheduled">

<scheduled_method

timeout_seconds="0"

interval="week"

exec="/my-method"/>

<instance enabled="true" name="default"/>

</service>

</service_bundle>


This service will execute the method '/my-method' once a week.


svcbundle(1M) fully supports scheduled services. In fact, this example was created using that tool with the invocation:


$ svcbundle -s service-name=example/scheduled -s instance-name=default -s start-method=/my-method -s interval=week


I took the liberty of trimming out some of less-interesting parts of the manifest so that it's easier to see the scheduled_method element. svcbundle(1M) knows all about constraints and reference points, and will try very hard to make sure it won't generate an invalid schedule.


Here are two more scheduled_method elements to illustrate some more interesting schedules:


<scheduled_method exec="/my-method"

timeout_seconds="0"

interval="year"

weekday_of_month="4"

month="November"

day="Thursday"/>


This schedule runs on US Thanksgiving once a year.


<scheduled_method exec="/my-method"

timeout_seconds="0"

interval="month"

frequency="2"

month="June"

year="2027"/>


This schedule runs every two months, counting from June of 2027.


And that's pretty much it. In a follow-up post, we'll dig into inpsecting scheduled services using the standard suite of SMF tools.  Stay tuned.

Be the first to comment

Comments ( 0 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.Captcha