Choosier cron runs

hook_cron() is widely implemented in the Drupal ecosystem – but what if your modules have varying frequency needs? For example, perhaps you'd like your aggregator feeds to update every fifteen minutes, and notifications should fire every minute to keep emails timely. But system_cron() should run as infrequently as practicable, because it calls cache_clear_all()!

Here is a small cron.php replacement that accomplishes this task. Just plunk the file in your drupal root directory. (You could move it to your sites folder if you modified the include path.) Different cron jobs for each module or set of modules can now be configured.

<?php
// $Id$
 
/**
 * @file
 * Handles incoming requests to fire off regularly-scheduled tasks (cron jobs).
 *
 * The file executes cron hooks selectively, instead of all-or-nothing.
 * This allows cron jobs to be configured with variable frequency.
 * Example usage:
 * * * * * * curl example.com/cron_selective.php?modules=notifications
 * *∕15 * * * * curl example.com/cron_selective.php?modules=aggregator
 * 0 0 * * * curl example.com/cron_selective.php?modules=system,dblog
 *
 */
 
include_once './includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
 
$modules = array_intersect(module_list(), explode(',', $_GET['modules']));
 
drupal_cron_run_selective($modules);
 
/**
 * Executes a cron run when called
 * @return
 * Returns TRUE if ran successfully
 */
function drupal_cron_run_selective($modules) {
  // If not in 'safe mode', increase the maximum execution time:
  if (!ini_get('safe_mode')) {
    set_time_limit(240);
  }
 
  // Fetch the cron semaphore
  $semaphore = variable_get('cron_semaphore', FALSE);
 
  if ($semaphore) {
    if (time() - $semaphore > 3600) {
      // Either cron has been running for more than an hour or the semaphore
      // was not reset due to a database error.
      watchdog('cron', 'Cron has been running for more than an hour and is most likely stuck.', array(), WATCHDOG_ERROR);
 
      // Release cron semaphore
      variable_del('cron_semaphore');
    }
    else {
      // Cron is still running normally.
      watchdog('cron', 'Attempting to re-run cron while it is already running.', array(), WATCHDOG_WARNING);
    }
  }
  else {
    // Register shutdown callback
    register_shutdown_function('drupal_cron_cleanup');
 
    // Lock cron semaphore
    variable_set('cron_semaphore', time());
 
    // Iterate through the modules calling their cron handlers (if any):
    foreach ($modules as $module) {
      module_invoke($module, 'cron');
      watchdog('cron', 'Selective cron run completed for %module.', array('%module' => $module), WATCHDOG_NOTICE);
    }
 
    // Release cron semaphore
    variable_del('cron_semaphore');
  }
}

Tagged as: cron, Drupal

10 comments

mikeytown (not verified) wrote 1 year 10 weeks ago

Elegant Solution

It's amazing how this one line makes the magic happen

$modules = array_intersect(module_list(), explode(',', $_GET['modules']));

Do you know if any of the contributed cron modules out there have similar functionality?
http://drupal.org/project/elysia_cron
http://drupal.org/project/supercron

I'll be linking to here from the boost issue queue.
http://drupal.org/node/331537

ps should you put some sort of wrapper around the get for security reasons?

perusio (not verified) wrote 1 year 10 weeks ago

elysia cron

You can do the same using the elysia_cron module. I've never tried supercron.

The caveat with elysia cron is that you need to replace the core provided version of cron.php with a version provided by the module or change the cron job command in crontab to point to the module's cron.php.

Th syntax for specifying jobs is crontab like.

Piloro (not verified) wrote 1 year 9 weeks ago

Elysia cron and supercron

Elysia cron can run without replacing cron.php or calling another cron.php (you can do that just to increase performances a little).
The only thing needed is a change in the system crontab to run the standard cron.php every minute (or what's the frequency you need).

Supercron is working in a way to do a similar thing (execute a group of task in a selectable time period), but it's still work in progress.

mikeytown (not verified) wrote 1 year 9 weeks ago

Command Line

If cron.php could take command line input as well, that would be a great feature.
http://php.net/commandline
http://php.net/reserved.variables.argv

mikeytown (not verified) wrote 1 year 9 weeks ago

D7 Issue

Found the core issue for this feature request
http://drupal.org/node/19173

balaji (not verified) wrote 1 year 7 weeks ago

great idea

Hai,

Thanks for sharing this info.It will be useful for everyone who are building a corporate or business websites using drupal

Thanks

mikeytown (not verified) wrote 1 year 7 weeks ago

Spam

rel="nofollow" only works for the homepage field, not for embedded links like the above.

Willem (not verified) wrote 44 weeks 21 hours ago

Elysia cron and supercron

I tried both supercron and elysia cron. Elysia cron can do what the above script does and lists all active cron jobs. Supercron can not be configured to run seperate tasks at custom intervals but like Elysia cron it list a complete overview of active cron tasks.

wedding (not verified) wrote 34 weeks 3 days ago

Oops~Your post is of great

Oops~Your post is of great value for a guy like me which is learning some basic web knowledge to get my own web to work.Thanks for your great job~

Visitor (not verified) wrote 30 weeks 4 days ago

How can I used wiht boost

Hi,

I'm triying to used the script with the module boost with the next cron sentence:
.... /cron_selective.php?modules=boost

But the expirated pages are not clear, it's the right mode to call the cron for this module.

Regards.

Add your comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>. Beside the tag style "<foo>" it is also possible to use "[foo]".

More information about formatting options