United States|United Kingdom|India
sudeepg
Apr 09, 2010

Challenge with Drupal 6 Cron

 

  Drupal cron getting stucked is quite a common problem with Drupal 6 and I found out an interesting way to figure out the reason why it is getting stuck.

 

Logging as always

 

As always, the solution is to log at the correct place. Drupal cron is invoked at includes/common.inc in the function drupal_cron_run (around line 2727), so we begin here logging into watchdog. We have to start logging when the cron starts for a particular module and when it finishes as follows:

 

   foreach (module_implements('cron') as $module) {                    
  watchdog('cron', t('Cron processing initiated for module: @module.', array('@module' => $module)));
    $function = $module .'_cron';                                     
      if ($log_timing) {                                                
        timer_start($function);                                         
        if ($log_timing == 'debug') {                                   
          watchdog('cron', t('Cron processing initiated for module: @module.', array('@module' => $module)));
        }                                                                                                    
      }                                                                                                      
      $function();                                                                                           
      if ($log_timing) {                                                                                     
        $timer = timer_stop($function);                                                                      
        watchdog('cron', t('Cron time elapsed for @module is @millisecs ms.', array('@module' => $module, '@millisecs' => $timer['time'])));
      }                                                                                                                                     

Cron has been running for more than an hour and is most likely stuck.

 

Also, notice it is quite common that your are getting this message:

"Cron has been running for more than an hour and is most likely stuck."

This means the cron is locked and therefore, we  would need to delete the semaphore variable to get the cron to work again.


function drupal_cron_run() {      
  // If not in 'safe mode', increase the maximum execution time:
     variable_del('cron_semaphore');

Now, run http://www.example.com/cron.php and watch your logs.

 

IMPORTANT NOTE: Don't forget to comment this line from this function after your cron runs successfully.

 

I had issues with cron run on search module. I skipped search module as follows as everything went well after that.

/**
 * Executes a cron run when called
 * @return                        
 * Returns TRUE if ran successfully
 */                                
function drupal_cron_run() {       
  // If not in 'safe mode', increase the maximum execution time:
     variable_del('cron_semaphore');
  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', t('Cron has been running for more than an hour and is most likely stuck.'), WATCHDOG_ERROR);

      // Release cron semaphore
      variable_del('cron_semaphore');
    }                                
    else {                           
      // Cron is still running normally.
      watchdog('cron', t('Attempting to re-run cron while it is already running.'), 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):
    // module_invoke_all('cron');    
    $log_timing = variable_get('cron_log_times', '1');                  
    foreach (module_implements('cron') as $module) {                    
          watchdog('cron', t('Cron processing initiated for module: @module.', array('@module' => $module)));
 if ($module == "search") continue; 
    $function = $module .'_cron';                                     
      if ($log_timing) {                                                
        timer_start($function);                                         
        if ($log_timing == 'debug') {                                   
          watchdog('cron', t('Cron processing initiated for module: @module.', array('@module' => $module)));
        }                                                                                                    
      }                                                                                                      
      $function();                                                                                           
      if ($log_timing) {                                                                                     
        $timer = timer_stop($function);                                                                      
        watchdog('cron', t('Cron time elapsed for @module is @millisecs ms.', array('@module' => $module, '@millisecs' => $timer['time'])));
      }                                                                                                                                     
    }                                                                                                                                       
    // Record cron time
    variable_set('cron_last', time());
    watchdog('cron', t('Cron run completed.'), WATCHDOG_NOTICE);

    // Release cron semaphore
    variable_del('cron_semaphore');

    // Return TRUE so other functions can check if it did run successfully
    return TRUE;                                                          
  }                                                                       
} 

 

Search Cron Handled Separately

 

In order to run search cron, I wrote another hook_menu function to update search indexes and that worked well. This hook menu was called on cron from linux shell.

 

<?php
  register_shutdown_function('search_update_totals');

  // Update word index
  foreach (module_list() as $module) {
    module_invoke($module, 'update_index');
  }
?>