Tuesday, May 10, 2011

Do You Speak Cronish?

A while back, I spoke about writing a cron dsl. Well, some progress has been made.


How do you talk about cron? Do you say that a job runs every day at midnight? Well if you do, then you need no further instructions on how to create your crons programmatically. Some example of some crons:

Update: I should have run the text in the console before output wrong data.

"Every day at midnight".crons == "0 0 * * *"
"Every 14 days at midnight".crons == "0 0 */14 * *"
"Every day on the weekday in June, July, and August at 3:30".crons == "30 3 * 6,7,8 1-5"

We all speak cronish to some degree!

The Syntax

One night, I decided to break down a cron statement into some determinable blocks. I came up with the following grammar rules:

  1. Incrementing statements
  2. Connectors
  3. Values / Descriptors

Incrementing Statements

Incrementals is the keyword every. This produces the famous *. Any numeric value you punch in after every makes it one of these: */n. A cron statement must start with one of these. Therefore, the shortest incremental time you can do, is something like:

// second, minute, hour, day of month, month, day of week, year
"Every second".cron == Cron("*", "*", "*", "*", "*", "*", "*")


The connectors I've chosen help make an English sentence regarding a cron job clear. Here's the run down:

  1. at refers only to time, which includes seconds, minutes, and hours. ie: at 4am and 4pm
  2. on refers to day values, particularly day of week values. ie: on Friday, Saturday, and Sunday
  3. in refers to month values. ie: in January to May
  4. on the nth refers to day of month values. ie: on the 1st, 2nd, 3rd, and 4th day
  5. in the year n is special syntax for a year value.

Connectors can be strung together with other connectors or incrementals. Some examples would be:

"Every day at midnight in every month".crons ==
"Every month at midnight on every day".crons

"every year in July on the weekend at 1pm-4pm".crons ==
"every day on the weekend at 1pm-4pm in July".crons

Just follow the simple rules, and it's pretty easy to build your time.

Values / Descriptors

Descriptors are just more keywords we use in English to describe something. These are:

  1. midnight and noon
  2. n:n:n for full clock description.
  3. other in the incrementals instead of 2.
  4. am and pm for hours.
  5. st, nd, rd and th for days in the month.
  6. weekend and weekday
  7. last applies for day of week and day of month.

The values are either numeric or English values for fields. Days are Monday - Sunday, months are January - December, and day of month are simply numbers.

Scala Cron Job

Describing a cron job in pure Scala is also done through dsl type speak. The syntax is heavily borrowed from sbt's task creation.

val payroll = task {
  println("Getting paid today ... with virtual cash!")
} executes "every Friday on the last day in every month"

// And we're off!
// Alternatively you could have written it like this

val visitation = task {
  println("Greetings, my name is Mouth Mouthman.")

visitation executes "every Wednesday at 6pm"
visitation executes "every Sunday at 3pm"

// Kill a job with stop
payroll stop // Oh noes!

Where do we go from here?

There's a lot of work that still needs to happen before this could be released. Cronish is freely available at my github. I'm working towards a stable release.

-- Philip Cali

No comments:

Post a Comment