Skip to main content
Image
Reloj

Custom Drupal Cron configuration

Hello everyone! I apologize for my absence these months, but I have been in a stage of new things and changes and I needed some time to settle it and come back stronger.

Every day we wake up in the morning, have breakfast, get dressed, brush our teeth, comb our hair... and well, we do all those daily tasks to start the day. If we don't do these things we feel like we are missing something. Drupal 8's cron works in a similar way.

What is it?

The term 'cron' refers to the automated tasks that a Drupal 8 portal executes every certain period of time or when the administrator wants; The time is fully configurable. It is responsible, among other things, for checking if there are available updates for the Drupal core, for contributed modules and themes, indexing portal searches, clearing internal caches, etc. It is nothing more and nothing less than a series of automated tasks that are responsible for maintaining the portal, but its functionality can go much further.

The cron at the interface level

By default, cron runs every three hours, but this can be configured and even launched manually from the interface itself (or code) in Settings > System > Cron . It is always advisable to take a look at the 'Status Report' from Reports > Status Report every time you finish running the cron to check if you have found any new updates or problems. Any user with the appropriate permissions can run the cron from the administration interface.

It is possible that from time to time we receive an error when launching the cron where it blocks and throws an exception indicating that it has not been carried out. This occurs when, for example, the cron is launched from different users or repeatedly. To unlock it we must execute a query in the database or do it directly from drush:

drush sqlq "DELETE FROM semaphore WHERE name = 'cron';"

The cron at the code level

The possibilities of 'playing' with cron are extensive. Cron not only takes care of the maintenance tasks mentioned above, it can also take care of custom processes that are defined in the code. To do this, the Drupal 8 API provides us with the hook_cron, which offers us to add functionalities during the execution of the cron, allowing the developer to implement multiple custom tasks or maintenance to the portal, independently of what Drupal does. It is important to note that the cron will always involve a temporary cost of performance on the portal, since the web server will be busy maintaining it and will not be able to serve other requests during the process. Therefore, it would be necessary to study whether implementations such as mass sending of emails, tasks in files or users, etc. excessively affect the performance of the site.

At the code level it is also possible to run the cron:

\Drupal::lock()->release('cron');

Let's imagine that our client asks us to encrypt the data of users who have been inactive on the portal for X amount of time due to data protection law. To achieve this, we have no choice but to periodically check the last access of all portal users and encrypt the data if the time conditions are met. The time conditions are regulated by the site administrator from the configuration in the interface, where they will regulate the time limit that a user must not reach for their data to be encrypted.

To do this we have created a custom module and form in the appropriate path (in the site administration settings). We will see how this can be done in a future post. As can be seen in the previous image, the site administrator will be able to set the time limit (in days) of the last login that a user must exceed for their data to be encrypted.

/**
 * Implements hook_cron().
 */
function mymodule_module_cron() {
  $connection = \Drupal::database();
  $current_day = date('d', \Drupal::time()->getCurrentTime());
  $type = $current_day % 2 ? 1 : 0;

  $config = \Drupal::service('config.factory')->get('encryption_settings_form.settings');
  if ($type == 0) {
    // Encriptar datos de usuarios con roles 'Pros' y 'Experts'.
  } else {
    // Encriptar datos de usuarios con roles 'Noobies'.
  }
}

As we see in the previous code, we are going to divide the user encryption depending on whether the current day is even or odd. This will ensure that checking all users will overload the server as little as possible. We will leave even days to encrypt users with 'Pros and 'Experts' roles and odd days for 'Noobies' users. This is done because users with 'Pros' and 'Experts' roles will be users who have previously paid or contracted a service, while 'Noobies' users will be those who have not paid and are using a free service from our portal, for example. which there will be more users of this last role. We are also loading and saving the interface configuration in $config. Finally it would be something like this:

/**
 * Implements hook_cron().
 */
function mymodule_module_cron() {
  $connection = \Drupal::database();
  $current_day = date('d', \Drupal::time()->getCurrentTime());
  $type = $current_day % 2 ? 1 : 0;

  $config = \Drupal::service('config.factory')->get('encryption_settings_form.settings');
  if ($type == 0) {
  	// Encriptar datos de usuarios con roles 'Pros' y 'Experts'.
  	// Capturamos la configuraciรณn, si no hay nada, seteamos por defecto a 365 dรญas (1 aรฑo)
    $days = empty($config->get('pros_experts_time_encrypt')) ? '365' : $config->get('pros_experts_time_encrypt');
    $current_date = date('m/d/Y', time());
    $final_date_timestamp = strtotime(date('Y-m-d', strtotime(
      '-' . $days . ' days', strtotime($current_date))));
    $users = \Drupal::entityQuery('user')
      ->condition('roles', ['pros', 'experts'], 'IN')
      ->condition('mail', '@', 'CONTAINS')
      ->condition('access', $final_date_timestamp, '<')
      ->execute();

    foreach ($users as $uid) {
      $account = User::load($uid);
      encryptUserData($connection, $account);
    }
  } else {
    // Encriptar datos de usuarios con roles 'Noobies'.
    // Capturamos la configuraciรณn, si no hay nada, seteamos por defecto a 365 dรญas (1 aรฑo)
    $days = empty($config->get('noobies_time_encrypt')) ? '365' : $config->get('noobies_time_encrypt');
    $current_date = date('m/d/Y', time());
    $final_date_timestamp = strtotime(date('Y-m-d', strtotime(
      '-' . $days . ' days', strtotime($current_date))));
    $users = \Drupal::entityQuery('user')
      ->condition('roles', 'noobies', '=')
      ->condition('mail', '@', 'CONTAINS')
      ->condition('access', $final_date_timestamp, '<')
      ->execute();
    foreach ($users as $uid) {
      $account = User::load($uid);
      encryptUserData($connection, $account);
    }
  }
}

We are launching the cron every day and it is responsible for periodically checking which users have a last access greater than that indicated in the configuration (see previous image). If the user has not connected for more than the time established in the configuration, or if it is empty after the default time of 365 days, the user's data will be encrypted. This is one of the many things that can be done with Drupal cronโ€ฆ

Conclusion

Drupal cron is essential to perform certain recurring tasks on our website. Furthermore, thanks to the Drupal 8 API we can create very interesting and extended implementations, without forgetting the performance cost to the server while it is running.

Join the Drupal Sapiens Community

Save content that interests you, connect with others in the community, contribute to win prizes and much more.

Login or create an account here

Latest posts

Featured

Last news