What is a cron job?
A cron job is just a plain old job that will run at specific intervals of time based on a cron expression.
How and where to schedule a cron job?
Cron jobs need to be scheduled on the bootstrap process and the Scheduler
will trigger those when the POST /api/v2/scheduler/cron
endpoint is hit.
What will differentiate a regular job from a cron job is the job descriptor used to schedule the job itself.
What is a job descriptor?
A JobDescriptorInterface
is used to describe a job. A Job descriptor doesn't change the job in any form, it just helps the Scheduler
to decide if the job needs to be run or not.
There are two main implementations of the interface NormalJobDescriptor
and CronJobDescriptor
.
A CronJobDescriptor
will take a Job and a cron expression as a parameter. A cron expression is a simple string that tells when you want to run the job. For example */5 * * * *
will run the job at every 5th minute.
Take a look at https://crontab.guru/ if you are not fully into cron expressions.
By design, the minimum granularity of a cron expression is 1 minute.
Example
$scheduler = $containter->get(SchedulerInterface::class);
// The job is meant to run every minute
$scheduler->addJobDescriptor(new CronJobDescriptor(EchoJob::class, '* * * * *'));
Scheduler's execution type
The Scheduler's JobExecutionType
will hint to the Scheduler
about what kind of job it should dispatch.
The default mode, JobExecutionType::normal()
, will be used in a regular request. JobExecutionType::cron()
will be used to hint the Scheduler about running cron jobs.
POST /api/v2/scheduler/cron
The most straightforward way to trigger a cron execution is using the POST /api/v2/scheduler/cron
endpoint.
POST /api/v2/scheduler/cron
will do the following:
- It will set the Scheduler on
JobExecutionType::cron()
- It will fire the event
CRON_TRIGGER_EVENT
- It will fire the Scheduler's dispatcher at the end of request (as any other request)
Why firing CRON_TRIGGER_EVENT
?
The event allows any listener to add cron jobs into the Scheduler
. Hooking into the event is NOT needed, it just gives you an additional opportunity to do so.
The use case in mind for this will be the following: To schedule a cron-job you need to run an intensive process (querying the database, contacting a remote service, etc), it would make no sense to do the calculation for every request, it will be better to do it just when you are sure a cron execution is running. The event helps you to be sure of that.
Because cron jobs will mainly be triggered when POST /api/v2/scheduler/cron
is hit, there are some special situations to consider.
The scheduler will run cron jobs at the defined minimum timespan (default of 1 minute). If you hit the endpoint more than once during the timespan, the jobs triggered on the second or following request will be abandoned.
For a cron job to be abandoned is the same as no hitting the endpoint. Why? Because the Scheduler
will take the last time it ran cron jobs to establish is any given cron job should run or not (based on the descriptor's schedule). As a consequence of this:
- No cron job will be missed in case the endpoint is not hit. They will run the next time.
- No cron job will run more than once in any given interval between two endpoint calls. For example:
*/10 * * * *
, should run every 10 minutes, however, if you are hitting the endpoint once an hour, the job will run one time (not 6) - If no information is available to know when the
Scheduler
ran cron jobs for the last time, one day in the past will be used as default. - Vanilla Cloud will hit
POST /api/v2/scheduler/cron
around every 5 minutes.
Vanilla Cloud - Feature flag
To enable the cron functionality on Vanilla Cloud, you need to set the site configuration Garden.Scheduler.Token
Configurations
Garden.Scheduler.Token
: Mandatory. Authentication token for accessing POST /api/v2/scheduler/cron
Garden.Scheduler.CronMinimumTimeSpan
: Optional. The minimum amount of time between two consecutive cron triggers. Default 60
seconds.
Troubleshooting
I am working locally and my cron job is not running. What should I check?
- Did you set
Garden.Scheduler.Token
? - Did you hit the
POST /api/v2/scheduler/cron
endpoint? - Did you pass your
Garden.Scheduler.Token
into the Authorization
header when you called POST /api/v2/scheduler/cron
? - Did you wait for
Garden.Scheduler.CronMinimumTimeSpan
between calls to the endpoint? Tip: Set Garden.Scheduler.CronMinimumTimeSpan
to a very low value - Was your job scheduled when you hit
POST /api/v2/scheduler/cron
?