Page cover image

All about CRON

Not corn, but close...

What about a CRON?

CRON strings are a concise way of telling the application when to schedule or run something. Perigee uses CRON string data throughout for advanced process scheduling and events.

CRON Data Explanation

Most CRON strings contain five bits. Perigee's CRON can contain 6 if you use the optional seconds bit.

Second   Minute      Hour      Day      Month      Day-Of-Week
   *        *         *         *         *            *
  • The ASTERISK character means "All Available Values"

    • For hour, this is 0-23

    • For Minute, this is 0-59

    • For Day this is 1-31

    • For Month this is 1-12

    • For Day-Of-Week this is 0-6 (Sunday being 0)

  • The COMMA character is a list of values

    • If the Month bit is 0,1,2 - Then the CRON is only run in Jan, Feb and March.

  • The DASH character means a range from a-z.

    • If the day bit is 0-6 - Then the CRON is only run the first 7 days of the month

  • The SLASH character is a divider of all available values.

    • If the second bit is */5 - Then the CRON is executed on every fifth second.

  • There are several special characters that can only be used in certain situations.

    • The F character is for FIRST OF:

      • This can be used in the Day or Day-Of-Week bits

      • In the day bit, F - The CRON would run the first day of the month

    • The L character is for LAST OF:

      • This can be used in the Day or Day-Of-Week bits

      • In the day bit, L-2 - The CRON would run the second from last day of the month

    • The # is for day-of-week selector

      • This is only used in the Day-Of-Week bit:

      • 0#2 would be the second Sunday (0 Sunday #2)

      • 1#3 would be the third Monday (1 Monday #3)

Examples

How would I run a CRON every morning at 5AM ?

  • Let's leave out the seconds since we don't need that here.

  • If we don't specify 0 in the minute bit the CRON it will run every minute of 5AM.

  • 5AM is 5 in the hour bit.

  • The key request is "every day", so let's set the day bit to an asterisk.

  • Every other

0 5 * * *

How would I run a CRON at 1AM on the last Friday of every month?

  • This is where that special L character comes into play.

    • Day-Of-Week starts as 0 Sunday, so Friday would be 5.

    • Asking for the last friday of the month would be L5 in day-of-week bit.

  • If we don't specify 0 in the minute bit the CRON it will run every minute of 1AM.

  • 1AM in the hour bit is 1

  • Asterisks for the other fields

0 1 * * L5

How would I run a CRON at 1AM on the second to last day of the month?

  • This is where that special L character comes into play again.

    • Asking for the second to last day of of the month would be L-2 in day bit.

  • If we don't specify 0 in the minute bit the CRON it will run every minute of 1AM.

  • 1AM is the hour bit is 1

  • Asterisks for the other bits

0 1 L-2 * *

The SDK

Parse

Call Parse on any CRON string. It will detect if seconds are present.

var cparsed = Cron.Parse("0 1 * * 0#1");

Occurrence

Get the next occurrence from a given date or supply a different time zone to find the next occurrence in that time zone.

var nOcc = cparsed.GetNextOccurrence(DateTimeOffset.Now);

//You can also supply a timezone:
var nOcc = cparsed.GetNextOccurrence(DateTimeOffset.Now, TimeZoneInfo.Utc);

You can use that parsed CRON to display info about it.

Console.WriteLine(cparsed.ToString());
//Prints: on minute 0 on hour 1 on the 1st Sunday

Inverse Period

The only other method you may care about is the InversePeriod. InversePeriod is interesting as it takes the CRON string and determines how consecutively it runs.

var inv = Cron.Parse("* 1-2 * * *").GetInversePeriod(DateTimeOffset.Now);
Console.WriteLine($"From {inv.Item1:G} to {inv.Item2:G}");

//Prints: From 1/1/2023 1:00:00 AM to 1/1/2023 2:59:00 AM

Notice how this CRON would run from 1AM consistently at every interval (minute) inclusively to 2:59AM? This method is an interesting way to use CRON data to specify ranges of time.

CRON in Perigee

There are bunch of ways to use CRON strings in Perigee. Let's take a look at a few:

Agents

SyncAgents use CRON strings to determine when to run, and even when to create blackout periods. You can see more in the linked section. Here's a quick preview!

taskConfig.AddAgent("DailySync", "DailySync", "DailyDB", 
new SyncAgentSourceMemory("SA.json"), AgentRunCondition.RunIfPastDue,

(configAgent) => configAgent.SetSyncLimitPerDay(2).SetSync(null, "55 6 * * *"),

(ct, l, executeHandler) => 
    DailySync.sync(taskConfig, taskConfig.CTS.Token, log, executeHandler, "DailyDB"),

(ct, l, treeHandler) => { },

TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(10), false)
    .LinkToConfig("Agents:DailySyncEnabled");

BlockUntil

This is a handy way of creating an awaitable task, or thread blocking mechanism using a CRON string.

//Async wait until the 0th second of every 5th minute
await PerigeeUtil.BlockUntil("0 */5 * * * *");

//Or for non async methods
PerigeeUtil.BlockUntil("0 */5 * * * *").GetAwaiter().GetResult();

Methods using CRON

As part of the core set of events in Perigee, you can easily add CRON methods.

PerigeeApplication.ApplicationNoInit("Crons", (c) =>
{
    c.AddCRON("CronMethod", "0 */5 * * * *", (ct, l) => {
        //Run's every 5 minutes at second 0
    });

});

CRON Testing Resources

A method to parse and print

A handy little method to print the definition of a CRON string, as well as print the next occurrence:

void PrintCRON(string inputStr)
{
    Console.WriteLine(inputStr);
    var cparsed = Cron.Parse(inputStr);
    Console.WriteLine(cparsed.ToString());
    var nOcc = cparsed.GetNextOccurrence(DateTimeOffset.Now);
    Console.WriteLine(nOcc.Value.ToString("G") + Environment.NewLine);
}

A site to test CRON data

This is an amazing site to visually and instantly see the results of a CRON.

Last updated