Handling different types of cron jobs using Schedule Expressions with AWS
I’ve been working on a few different cron jobs recently and one of things I’ve come up against is just making no-nonsense scheduled cron jobs. I’ve noticed that some of the things I was working on just weren’t documented as clearly as I’d like them to be and I figured I would share a couple of different common schedule expressions that I’ve had to use.
Schedule Expressions
There are two types of schedule expressions that are used in AWS, rate or cron. All of the expressions are defined as strings which are parsed and stored on EventBridge, then later executed when the timed trigger is met. https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-create-rule-schedule.html
Rate
When we use rate, it’s defined as a frequency by which your lambda or other service is invoked by EventBridge. Rate is a function that takes a positive integer and a frequency.
Possible Frequencies
minute|minutes|hour|hours|day|days
The rate definition looks like the following:
rate(value unit)
So, all you have to do to define this is:
Every minute:
rate(1 minute)
Every 30 minutes:rate(30 minutes)
Every hour:rate(1 hour)
Every 12 hours:rate(12 hours)
Every day:rate(1 day)
Every week:rate(7 days)
Every two weeks:rate(14 days)
Every three weeks:rate(21 days)
Keep in mind the pluralities of the different units. It should match the value. So, you can’t do something like rate(1 months)
or rate(2 hour)
.
Super simple, right? But what if you need to do something a little more complex, like you need a very specific time or you want to execute on a specific day of the week or month. That’s where cron jobs come in, but it’s also where things can be a little trickier.
Cron
Crons are scheduled jobs that can execute your lambda or other services using EventBridge. The formatting of crons is a little different and more complex than the rates. If you wanted to define a cron it takes the following format:
cron(
Minutes
Hours
Day-of-month
Month
Day-of-week
Year
)
Here’s a few common definitions that I’ve had to use in the past:
Every day(at 11:59pm):
cron(59 23 * * ? *)
Every week(on Sunday at 11:59pm):
cron(59 23 ? * SUN *)
Every quarter(AKA 3 months):
cron(0 0 * */3 ? *)
Every year on January first:
cron(0 0 1 1 * *)
Depending on your use case things might get more or less complex, but the chart below should help you a little bit with coming up with your cron definition:
Minutes | Hours | Day of Month | Month | Day of Week | Year
---------|-------|--------------|-----------------|----------------|-----------
0-59 | 0-23 | 1-31 | 1-12 or JAN-DEC | 1-7 or SUN-SAT | 1970-2199
There are also wildcards that can be used in certain situations.
Comma
Commas are used to define multiple values for a particular field value. For instance, if you wanted it to run on two different months like both January
and March
, then you could write them as a comma separated value:
Every January 1st and March 1st:
cron(* * 1 JAN,MAR ? *)
Dash
Dashes are used to denote a range of values. For example if I wanted to run every single day of the month between the 1st and the 15th:
Everyday between the1st and 15th of every month:
cron(* * 1-15 * ? *)
Asterisk
As per usual, the asterisk includes all of the possible values in the list.
Everyday at 12pm:
cron(0 12 * * ? *)
Forward Slash
The forward slash allows for increments. For months, you can do increments of 3 by using */3
, as shown in my example above for the quarterly cron job.
Question Mark
The question mark is used as a placeholder for any. This is used due to one of the limitations explained below. You can only define either day of the month
or day of the week
since they could be conflicting values. The days of the month don’t necessarily fall on the day of the week. In many of the examples above, you can see this in use.
L
L
stands for the last day of either the week or month. It can be used with day of the month
or day of the week.
All you need to do is append the L to your value.
Last day of the month every month:
cron(* * 3L * ? *)
Last day of the week every week:
cron(* * ? * 3L *)
W
W
stands for weekday. In the day of month
field you can use this to define specific weekdays within the month. This is perfect for times when you need notifications to go out during a work week.
Every weekday closest to the 15th of the month:
cron(* * 15W * ? *)
#
The #
symbol is used in the day of the week
field to a specific occurrence of a day within a month. For example, the 3rd Wednesday of a month. The syntax for this is day-of-the-week#occurrence-within-month
.
Every 3rd Wednesday of the month:
cron(* * ? * 4#3 *)
List of all Wildcards relative to their fields
Field | Wildcards
--------------|---------------
Minutes | , - * /
Hours | , - * /
Day of Month | , - * ? / L W
Month | , - * /
Day of Week | , - * ? L #
Year | , - * /
Limitations
Let’s talk about the limitations of the cron function.
- The
day of week
field can only use one expression. I.E. you can’t combine3#4,3#5
. - As mentioned above, you can only specify either the
day of the month
or theday of the week
because they could be conflicting. The 2nd of every month isn’t a Tuesday. So, when you define one of them, you’ll need to use a?
for the other one. - Cron expressions can’t fire off at rates that are less than 1 minute.
Hopefully, this article will help assist on the understanding of scheduled events in AWS using EventBridge. I know that all of this information is freely available through AWS Documentation, but I sometimes find that hard to read.
If there are any scheduled cron jobs that you have questions about please ask in the comments! I’m hoping to be able to write more content about AWS, Serverless Stack(SST), Typescript, React, and much more. I’m also thinking about making a package that will export human readable variables that contain different cron settings. Let me know if that’s something that you’d like to use.
This is my first published article, so please let me know if there is anything I can do to improve readability or if there are subjects that you’d like to know about. Thanks for sticking around to the end!