Guide to Ultimate Cron

Drupal comes with its own built in cron. This means that you can add your own job to the list of jobs that are executed when the Drupal cron runs.

Drupal runs all of these jobs at the same time. What happens if you want to run one particular cron job really frequently? You have to change your cron settings to run ALL of them that frequently. It’s an all or nothing affair and you end up running all the cron jobs as often as your most frequent job. That can put a lot of pressure on your web server.

A second problem is if you have a job that requires a lot of heavy lifting. With these jobs, you might want to run them overnight when traffic to your site is lighter and there is less pressure on the web server. But with Drupal’s built in cron, you can’t do that either because of the all or nothing nature of it. You run it once or not at all.

To solve this problem, you need a way to separate cron jobs so that you can run each job, or groups of jobs, at different times. There are two main options to achieve that - Elysia Cron and Ultimate Cron. In this article, we are going to look at Ultimate Cron because that is available for Drupal 7 and 8, where as Elysia Cron is Drupal 7 only.

Download and install the module

In Drupal 8, the recommended way to add a new module to your project is to use composer. The following composer command will download Ultimate Cron and add it to the list of dependencies.

composer require drupal/ultimate_cron

You can then enable the module manually by going to the Extend admin menu item, or by using Drush.

Create a new job

You can create a new job by implementing hook_cron() in a custom module. The following example implements hook_cron() in a module called custom_utility. When this job is run, it will log a message to Drupal’s logs.

function custom_utility_cron() {
  \Drupal::logger('custom_utility')->notice('Cron ran');
}

You can change the code in the function to execute what you need. The call to log a message is purely to demonstrate that this cron job is actually running.

Discover the job

Head over to configuration -> cron in the admin menu (/admin/config/system/cron/jobs). You should see a list of jobs from various core modules.

Hit the Discover jobs button and the job you created above will appear on the list.

Ultimate cron jobs

To test that this works, click Run. Then head over to recent log messages (admin/reports/dblog) and you should see the message.

Message in log from ultimate cron

To edit the frequency of the job, click on the arrow to the right of the Run button and click edit. In the scheduler tab you can change the frequency in the Run cron every X minutes drop down to.

Export the configuration

At this point, you can export the configuration using Drupal’s standard configuration export. You can then import the configuration if you use a staging and production site. If you are unsure how to export and import configuration, check out the configuration management documentation on Drupal.org.

Adding more than one job for a module

If your custom module only needs to support one cron job, then you have enough to do that. You can add additional code to your implementation of hook_cron() (see custom_utility_cron() above) and that will run when your cron job runs at the scheduled time.

But what if you want to have more than one cron job running at different times all from this one custom module?

You can do this by defining each multiple cron job with their own call back function. The call back function is used instead of hook_cron().

The settings for each Ultimate Cron job is stored in its own configuration file. Drupal uses YAML for configuration files, and you’ll need to create these files. The following steps will outline how to do this.

Steps to add a cron job

  1. In the admin menu, go to Configuration -> Configuration synchronisation (/admin/config/development/configuration)
  2. Click on the Export tab and then the Single item sub-tab (/admin/config/development/configuration/single/export)
  3. Change Configuration type to Cron job
  4. Change Configuration name to Default cron handler with the name of your custom module. In my case, this is  Default cron handler (custom_utility_cron).
  5. Copy the configuration code to your clipboard

In your custom module:

  1. Create a config directory in the root of your custom module’s directory
  2. Create a new file: ultimate_cron.job.jobname.yml (change jobname to the name of your job)
  3. Paste the configuration code you copied earlier

Here is an example of what this code will look like:

uuid: fa40bf2b-f544-4e22-b4b9-dda9cc0efbfe
langcode: en
status: true
dependencies:
  module:
    - custom_utility
title: 'Default cron handler'
id: custom_utility_cron
weight: 0
module: custom_utility
callback: custom_utility_cron
scheduler:
  id: simple
  configuration:
    rules:
      - '*/15+@ * * * *'
launcher:
  id: serial
  configuration:
    timeouts:
      lock_timeout: 3600
    launcher:
      thread: 0
logger:
  id: database
  configuration:
    method: '3'
    expire: 1209600
    retain: 1000

There are a couple of adjustments to make to this file:

  • Remove the uuid line (the first line)
  • Change the id to something unique e.g. id: custom_utility_cron_job1
  • Change the title to something meaningful so that you can distinguish this job in the cron admin page

This file is creating a new job for Drupal to run. Let’s break it down:

  • callback: custom_utilty_cron - this is the call back function that will be run when this job runs.
  • module: - this is your custom module. This is also the module where you should add your call back function
  • scheduler: - this is the schedule to which this job will run, which for this one is every 15 minutes

The next thing to do is to add the callback to the .module file in your module.

Here is an example:

/**
 * The callback for the cron job.
 */
function custom_utility_callback() {
  \Drupal::logger('custom_utility')->notice('Cron ran');
}

This call back function will be run every time this job is executed.

And then go back to the configuration file from above and change the callback function to point to this function. In my example, this means changing this line:

callback: custom_utility_cron

To:

callback: custom_utility_callback

Repeat

You can then repeat these steps for any additional cron jobs that you need, with a new configuration YAML file and call back function for each.

Import the new config

In order for this to work, you need to import the configuration that you set up above. This can be done with the following command (change custom_utility to the name of your module):

drush config-import --source=modules/custom/custom_utility/config --partial -y

Wrapping up

Separating cron jobs out is often necessary to give you the control you need to run jobs at different times. Ultimate Cron is a wonderful module that allows you to do just that.

If you liked this, you'll love my book, Conquer Drupal 8 Module Development.

Comments

Very good tutorial. Thank you.

Add new comment