Using a Drupal Cron job instead of an update hook

Pasan Gamage
2 min readJun 17, 2022

--

This article is a follow-up from my previous post

I’ve recently tried using cron jobs to run small tasks such as creating terms to a brand-new vocabulary that is not yet installed in the destination site during the deployment process as drush updb is executed prior drush config-import.

What we can do is commit the new vocabulary configurations into the codebase and add a hook_cron() with some logic to create terms programmatically into that vocabulary.

Code

Create a new custom module.

app/modules/custom/my_module/my_module.module

In the hook_cron() we need to use a Drupal state storage service.

This is because we DO NOT want the same term creation method to be executed every time a cron is triggered.

Below comment is from app/core/lib/Drupal::state()

* Use this to store machine-generated data, local to a specific environment
* that does not need deploying and does not need human editing; for example,
* the last time cron was run. Data which needs to be edited by humans and
* needs to be the same across development, production, etc. environments
* (for example, the system maintenance message) should use \Drupal::config() instead.

Since we won’t be finding any need for the state variables to be changed manually, let’s use a new variable named my_module.test_vocabulary.status

/**
* Implements hook_cron().
*
* Add methods here to be executed via cron.
*/
function my_module_cron() {
// Execute if my_module.test_vocabulary.status is TRUE.
if (!\Drupal::state()->get('my_module.test_vocabulary.status')) {
_my_module_create_test_vocabulary_terms();
}
}

In the first run the my_module.test_vocabulary.status is FALSE therefore the _my_module_create_test_vocabulary_terms() method will be executed. And in there we will set the my_module.test_vocabulary.status to TRUE

/**
* Create 'Test vocabulary' terms.
*/
function _my_module_create_test_vocabulary_terms() {
// TERM CREATION LOGIC GOES HERE


// Set state variable so that cron will not execute this method again.
\Drupal::state()->set('my_module.test_vocabulary.status', TRUE);
\Drupal::messenger()->addMessage('Test vocabulary terms created.');
}

Now we can manually trigger the cron job from admin/config/system/cron

Important

According to app/core/core.api::hook_cron() make sure no long-running task is added as cron task.

* Modules that require some commands to be executed periodically can
* implement hook_cron(). The engine will then call the hook whenever a cron
* run happens, as defined by the administrator. Typical tasks managed by
* hook_cron() are database maintenance, backups, recalculation of settings
* or parameters, automated mailing, and retrieving remote data.
*
* Short-running or non-resource-intensive tasks can be executed directly in
* the hook_cron() implementation.
*
* Long-running tasks and tasks that could time out, such as retrieving remote
* data, sending email, and intensive file tasks, should use the queue API
* instead of executing the tasks directly. To do this, first define one or
* more queues via a \Drupal\Core\Annotation\QueueWorker plugin. Then, add items
* that need to be processed to the defined queues.

Alternative solution

I will write a blog post about this solution, but for the moment please find below as a reference.

https://www.drush.org/latest/deploycommand/

Thanks Lee for this suggestion.

Resources

https://www.thirdandgrove.com/insights/best-practices-for-using-drupals-cron-system-hook_cron/

https://api.drupal.org/api/drupal/core%21core.api.php/function/hook_cron/10.0.x

--

--

Pasan Gamage
Pasan Gamage

Written by Pasan Gamage

Backend Developer | Motorbike enthusiast

No responses yet