You are here

ultimate_cron.module in Ultimate Cron 7

@todo Add filter on overview page. @todo Add log view (with graph). @todo Make proper markup for overview page. @todo Refactor drush stuff, too many intimate relations with Background Process @todo Refactor Cron % offset stuff. Too mixed up and ungrokable code-wise and 'delta' is not consistent.

hook_cron_alter(&$hooks) hook_cron_schedule_alter(&$hooks) hook_cron_pre_execute($name, $hook) hook_cron_pre_execute_FUNCTION($hook) hook_cron_post_execute($name, $hook) hook_cron_post_execute_FUNCTION($hook)

File

ultimate_cron.module
View source
<?php

/**
 * @file
 *
 * @todo Add filter on overview page.
 * @todo Add log view (with graph).
 * @todo Make proper markup for overview page.
 * @todo Refactor drush stuff, too many intimate relations with Background Process
 * @todo Refactor Cron % offset stuff. Too mixed up and ungrokable code-wise and 'delta' is not consistent.
 *
 * hook_cron_alter(&$hooks)
 * hook_cron_schedule_alter(&$hooks)
 * hook_cron_pre_execute($name, $hook)
 * hook_cron_pre_execute_FUNCTION($hook)
 * hook_cron_post_execute($name, $hook)
 * hook_cron_post_execute_FUNCTION($hook)
 */

/**
 * Maximum number of simultaneous connections.
 */
define('ULTIMATE_CRON_SIMULTANEOUS_CONNECTIONS', 40);

/**
 * Default handle prefix for background processes.
 */
define('ULTIMATE_CRON_HANDLE_PREFIX', 'uc:');

/**
 * Default rule.
 */
define('ULTIMATE_CRON_RULE', '*/10+@ * * * *');

/**
 * Default rule for easy hook "hourly".
 */
define('ULTIMATE_CRON_HOURLY_RULE', '0 * * * *');

/**
 * Default rule for easy hook "daily".
 */
define('ULTIMATE_CRON_DAILY_RULE', '0 0 * * *');

/**
 * Default rule for easy hook "weekly".
 */
define('ULTIMATE_CRON_WEEKLY_RULE', '0 0 * * 1');

/**
 * Default rule for easy hook "monthly".
 */
define('ULTIMATE_CRON_MONTHLY_RULE', '0 0 1 * *');

/**
 * Default rule for easy hook "yearly".
 */
define('ULTIMATE_CRON_YEARLY_RULE', '0 0 1 1 *');

/**
 * Default max execution time for Ultimate Cron.
 */
define('ULTIMATE_CRON_MAX_EXECUTION_TIME', 86400);

/**
 * Default catch up time for Ultimate Cron.
 */
define('ULTIMATE_CRON_CATCH_UP', 300);

/**
 * Default lease time for Ultimate Cron queues.
 */
define('ULTIMATE_CRON_QUEUE_LEASE_TIME', 30);

/**
 * Default clean up time for log entries (30 days).
 */
define('ULTIMATE_CRON_CLEANUP_LOG', 86400 * 30);

/**
 * Default setting for poorman.
 */
define('ULTIMATE_CRON_POORMAN', FALSE);

/**
 * Default queue polling latency.
 */
define('ULTIMATE_CRON_QUEUE_POLLING_LATENCY', '');

/**
 * Time in seconds to spend on launcing cron jobs.
 */
define('ULTIMATE_CRON_LAUNCH_WINDOW', 55);

/**
 * Time in seconds to spend on launcing cron jobs.
 */
define('ULTIMATE_CRON_SERVICE_GROUP', 'default');

// ---------- HOOKS ----------
module_load_include('nagios.inc', 'ultimate_cron');

/**
 * Implements hook_help().
 */
function ultimate_cron_help($path, $arg) {
  switch ($path) {
    case 'admin/help#ultimate_cron':

      // Return a line-break version of the module README
      return '<pre>' . file_get_contents(dirname(__FILE__) . '/README.txt') . '</pre>';
    case 'admin/build/cron':
      return '<p>' . t('Here you can see the crontab settings for each job available') . '</p>';
    case 'admin/build/cron/settings':
      return '<p>' . t('Here you can change the crontab settings for each job available') . '</p>';
  }
}

/**
 * Implements hook_menu().
 */
function ultimate_cron_menu() {
  $items = array();
  $items['admin/config/system/cron/settings'] = array(
    'title' => 'Settings',
    'description' => 'Cron settings',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'ultimate_cron_settings_form',
    ),
    'access arguments' => array(
      'administer ultimate cron',
    ),
    'type' => MENU_LOCAL_TASK,
    'file' => 'ultimate_cron.admin.inc',
  );
  $items['admin/config/system/cron/settings/%'] = array(
    'title' => 'Settings',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'ultimate_cron_function_settings_form',
      5,
    ),
    'access arguments' => array(
      'administer ultimate cron',
    ),
    'weight' => 0,
    'file' => 'ultimate_cron.admin.inc',
  );
  $weight = 0;
  foreach (array(
    'error' => 'Errors',
    'warning' => 'Warnings',
    'info' => 'Info',
    'success' => 'Success',
    'running' => 'Running',
  ) as $status => $title) {
    $items['admin/config/system/cron/overview/' . $status] = array(
      'title' => $title,
      'description' => 'View and manage cron table',
      'page callback' => 'ultimate_cron_view_page',
      'page arguments' => array(
        5,
      ),
      'access arguments' => array(
        'administer ultimate cron',
      ),
      'module' => 'ultimate_cron',
      'file' => 'ultimate_cron.admin.inc',
      'weight' => $weight++,
      'type' => MENU_LOCAL_TASK,
    );
  }
  $items['admin/config/system/cron/overview/all'] = array(
    'title' => 'All',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => $weight++,
  );
  $items['admin/reports/cron'] = array(
    'title' => 'Cron logs',
    'description' => 'View logs for all cron jobs.',
    'page callback' => 'ultimate_cron_view_page',
    'access arguments' => array(
      'administer ultimate cron',
    ),
    'file' => 'ultimate_cron.admin.inc',
  );
  $items['admin/reports/cron/%'] = array(
    'title' => 'Cron log',
    'description' => 'View log for specific function.',
    'page callback' => 'ultimate_cron_function_log_page',
    'page arguments' => array(
      3,
    ),
    'access arguments' => array(
      'administer ultimate cron',
    ),
    'file' => 'ultimate_cron.admin.inc',
  );
  $items['admin/ultimate-cron/service/start/%'] = array(
    'type' => MENU_CALLBACK,
    'title' => 'Run cron job',
    'description' => 'Run cron job',
    'page callback' => 'ultimate_cron_service_start',
    'page arguments' => array(
      4,
    ),
    'access arguments' => array(
      'administer ultimate cron',
    ),
    'file' => 'ultimate_cron.admin.inc',
  );
  $items['admin/ultimate-cron/service/enable/%'] = array(
    'type' => MENU_CALLBACK,
    'title' => 'Enable cron job',
    'description' => 'Enable cron job',
    'page callback' => 'ultimate_cron_service_enable',
    'page arguments' => array(
      4,
      TRUE,
    ),
    'access arguments' => array(
      'administer ultimate cron',
    ),
    'file' => 'ultimate_cron.admin.inc',
  );
  $items['admin/ultimate-cron/service/disable/%'] = array(
    'type' => MENU_CALLBACK,
    'title' => 'Disable cron job',
    'description' => 'Disable cron job',
    'page callback' => 'ultimate_cron_service_enable',
    'page arguments' => array(
      4,
      FALSE,
    ),
    'access arguments' => array(
      'administer ultimate cron',
    ),
    'file' => 'ultimate_cron.admin.inc',
  );
  $items['admin/ultimate-cron/service/process-status'] = array(
    'type' => MENU_CALLBACK,
    'title' => 'Cron job process status',
    'description' => 'Cron job process status',
    'page callback' => 'ultimate_cron_service_process_status',
    'access arguments' => array(
      'administer ultimate cron',
    ),
    'file' => 'ultimate_cron.admin.inc',
  );
  return $items;
}

/**
 * Implements hook_cron_queue_info().
 * Used for code injection in order to hijack cron runs.
 */
function ultimate_cron_cron_queue_info() {
  static $processed = FALSE;
  if (!$processed) {
    $processed = TRUE;
    if (basename($_SERVER['PHP_SELF']) == 'cron.php') {
      ultimate_cron_cron_run(FALSE);
      exit;
    }
  }
  return array();
}

/**
 * Implements hook_permission().
 */
function ultimate_cron_permission() {
  return array(
    'administer ultimate cron' => array(
      'title' => t('Administer Ultimate Cron'),
      'description' => t('Lets you configure everything in Ultimate Cron'),
    ),
  );
}

/**
 * The cron handler takes over the normal Drupal cron handler
 * and runs the normal hook_cron() plus the hook_cronapi().
 *
 * @param boolean $return
 *   return to caller if TRUE, otherwise exit().
 */
function ultimate_cron_cron_run($return = FALSE) {
  if (variable_get('install_task', FALSE) != 'done') {
    return;
  }

  // Be other cron module friendly
  if (_ultimate_cron_incompatible_modules()) {
    return;
  }

  // If run from core cron through CLI then don't do anything (drush core-cron)
  if (!$return && drupal_is_cli()) {
    return;
  }

  // Acquire lock
  if (!lock_acquire('cron', 240.0)) {
    drupal_set_message(t('Ultimate Cron launcher already running'), 'error');
    return;
  }
  $msc = variable_get('ultimate_cron_simultaneous_connections', ULTIMATE_CRON_SIMULTANEOUS_CONNECTIONS);

  // Get list of cron hooks.
  $hooks = ultimate_cron_get_hooks();

  // Get schedule.
  $schedule = ultimate_cron_get_schedule($hooks);
  drupal_set_message(t('%jobs jobs scheduled for launch', array(
    '%jobs' => count($schedule),
  )));

  // Start the jobs. Keep launching jobs until X seconds into the request.
  @set_time_limit(120);
  $time = time();
  $expire = $time + variable_get('ultimate_cron_launch_window', ULTIMATE_CRON_LAUNCH_WINDOW);
  $running = array();
  $launched = 0;
  $handle_prefix = variable_get('ultimate_cron_handle_prefix', ULTIMATE_CRON_HANDLE_PREFIX);

  // Try to launch jobs within the given time frame
  while (!empty($schedule) && time() < $expire) {
    $running_processes = db_select('background_process', 'bp')
      ->fields('bp', array(
      'handle',
    ))
      ->condition('bp.handle', $handle_prefix . '%', 'LIKE')
      ->countQuery()
      ->execute()
      ->fetchField();

    // Launch jobs.
    reset($schedule);
    while ((list($name, $hook) = each($schedule)) && time() < $expire) {

      // Congestion protection
      if (empty($hook['override_congestion_protection']) && $running_processes >= $msc) {
        continue;
      }
      if (empty($hook['force_run']) && !ultimate_cron_hook_should_run($hook)) {
        unset($schedule[$name]);
        continue;
      }
      $result = ultimate_cron_run_hook($name, $hook);

      // Handle errors.
      if ($result) {
        $handle = $handle_prefix . $name;
        $running[$handle] = $result;
        unset($schedule[$name]);
        $launched++;
        $running_processes++;
      }
      else {
        if ($result === FALSE) {

          // Could not get lock, skip job.
          unset($schedule[$name]);
        }
        else {

          // Failed to start, retry next time.
          watchdog('ultimate_cron', "Error starting {$name}", array(), WATCHDOG_WARNING);
        }
      }
    }

    // Jobs running ... check for start
    if ($running) {
      $result = db_query("SELECT p.name FROM {progress} p WHERE p.name IN (:running)", array(
        ':running' => array_keys($running),
      ));
      while ($handle = $result
        ->fetchObject()) {
        if (is_resource($running[$handle->name])) {
          fclose($running[$handle->name]);
        }
        unset($running[$handle->name]);
      }
    }
    sleep(1);
  }

  // Close all jobs left
  if ($running) {
    foreach (array_keys($running) as $handle) {
      if (is_resource($running[$handle])) {
        fclose($running[$handle]);
      }
      unset($running[$handle]);
    }
  }

  // Update drupals cron timestamp, but don't clear the cache for all variables!
  $name = 'cron_last';
  $value = time();
  global $conf;
  db_merge('variable')
    ->key(array(
    'name' => $name,
  ))
    ->fields(array(
    'value' => serialize($value),
  ))
    ->execute();
  $conf[$name] = $value;
  drupal_set_message(t('%jobs jobs launched', array(
    '%jobs' => $launched,
  )));
  if (count($schedule)) {
    drupal_set_message(t('%jobs jobs failed to launch within %seconds seconds', array(
      '%jobs' => count($schedule),
      '%seconds' => variable_get('ultimate_cron_launch_window', ULTIMATE_CRON_LAUNCH_WINDOW),
    )), empty($schedule) ? 'status' : 'error');
    watchdog('ultimate_cron', '%jobs jobs failed to launch within %seconds seconds', array(
      '%jobs' => count($schedule),
      '%seconds' => variable_get('ultimate_cron_launch_window', ULTIMATE_CRON_LAUNCH_WINDOW),
    ), WATCHDOG_WARNING);
  }

  // Release the lock
  lock_release('cron');

  // And we're done ...
  if ($return) {
    return empty($schedule);
  }
  else {
    exit;
  }
}

/**
 * Implements hook_cronapi().
 */
function ultimate_cron_cronapi($op, $job = NULL, $hook = NULL) {

  // Grab the defined cron queues.
  static $queues = NULL;
  if (!isset($queues)) {
    $queues = module_invoke_all('cron_queue_info');
    drupal_alter('cron_queue_info', $queues);
  }
  switch ($op) {
    case 'list':
      $jobs['ultimate_cron_cleanup_log'] = t('Cleanup log entries');
      foreach ($queues as $queue_name => $info) {
        $jobs['ultimate_cron_queue_' . $queue_name] = t('Queue: %name', array(
          '%name' => $queue_name,
        ));
      }
      return $jobs;
    case 'rule':
      $queue_name = preg_replace('/^ultimate_cron_queue_/', '', $job);
      if ($queue_name === $job) {
        return;
      }
      return '* * * * *';
    case 'execute':
      $queue_name = preg_replace('/^ultimate_cron_queue_/', '', $job);
      if ($queue_name === $job) {
        return;
      }
      $polling_latency = variable_get('ultimate_cron_queue_polling_latency', ULTIMATE_CRON_QUEUE_POLLING_LATENCY);
      $info = $queues[$queue_name];
      $function = $info['worker callback'];
      $end = time() + (isset($info['time']) ? $info['time'] : 15);
      $queue = DrupalQueue::get($queue_name);
      $items = 0;
      $settings = ultimate_cron_get_settings("ultimate_cron_queue_{$queue_name}");
      $polling_throttle = isset($settings['queue_polling_throttle']) ? $settings['queue_polling_throttle'] : 0;
      while (time() < $end) {
        $lease_time = isset($hook['settings']['queue_lease_time']) ? $hook['settings']['queue_lease_time'] : variable_get('ultimate_cron_queue_lease_time', ULTIMATE_CRON_QUEUE_LEASE_TIME);
        $item = $queue
          ->claimItem($lease_time);
        if (!$item) {
          if (is_numeric($polling_latency)) {
            usleep($polling_latency * 1000);
            continue;
          }
          else {
            break;
          }
        }
        try {
          if (is_numeric($polling_throttle)) {
            if ($items == 0) {

              // Move the boundary if using a throttle, to avoid waiting for nothing
              $end -= $polling_throttle / 1000;
            }
            else {

              // Sleep before retrieving
              usleep($polling_throttle * 1000);
            }
          }
          $function($item->data);
          $queue
            ->deleteItem($item);
          $items++;
        } catch (Exception $e) {

          // Just continue ...
          watchdog('ultimate_cron', "Queue item %item_id failed with message %message", array(
            '%item_id' => $item->item_id,
            '%message' => $e
              ->getMessage(),
          ), WATCHDOG_ERROR);
        }
      }
      drupal_set_message(t('Processed @items items', array(
        '@items' => $items,
      )));
      if (is_numeric($polling_latency)) {
        $settings = ultimate_cron_get_settings($job);
        $hook['settings'] = $settings + $hook['settings'];
        if (ultimate_cron_hook_should_run($hook)) {
          background_process_keepalive();
        }
      }
      return;
  }
}

/**
 * Implements hook_progress_message_alter().
 */
function ultimate_cron_progress_message_alter(&$message) {
  $pseudo_process = new stdClass();
  $pseudo_process->handle = $message->data->progress->name;
  $pseudo_process->start_stamp = $message->data->progress->start_stamp;
  $pseudo_process->progress = $message->data->progress->progress;
  $pseudo_process->exec_status = 2;
  $message->data->background_process = $pseudo_process;
  return ultimate_cron_background_process_message_alter($message);
}

/**
 * Implements hook_background_process_message_alter().
 */
function ultimate_cron_background_process_message_alter(&$message) {
  $handle_prefix = variable_get('ultimate_cron_handle_prefix', ULTIMATE_CRON_HANDLE_PREFIX);

  // Only alter Ultimate Cron background process messages
  if (substr($message->data->background_process->handle, 0, 3) !== $handle_prefix) {
    return;
  }
  $message->data->ultimate_cron['start_stamp'] = format_date((int) $message->data->background_process->start_stamp, 'custom', 'Y-m-d H:i:s');
  if ($message->data->background_process->progress >= 0) {
    $message->data->ultimate_cron['progress'] = gmdate('H:i:s', (int) (microtime(TRUE) - $message->data->background_process->start_stamp)) . sprintf(" (%3d%%)", $message->data->background_process->progress * 100);
  }
  $message->data->ultimate_cron['unlockURL'] = url('background-process/unlock/' . $message->data->background_process->handle, array(
    'query' => array(
      'destination' => 'admin/config/system/cron',
    ),
  ));
}

/**
 * Implements hook_theme_registry_alter().
 */
function ultimate_cron_theme_registry_alter(&$theme_registry) {
  $theme_registry['page']['theme paths'][] = drupal_get_path('module', 'ultimate_cron') . '/templates';
}

/**
 * Implements hook_watchdog().
 */
function ultimate_cron_watchdog($log = array()) {
  $record =& drupal_static('ultimate_cron_record', FALSE);
  if ($record) {
    $log['variables'] = is_array($log['variables']) ? $log['variables'] : array();
    ultimate_cron_record_log(t($log['message'], $log['variables']), FALSE, $log['severity']);
  }
}

/**
 * Implements hook_init().
 */
function ultimate_cron_init() {

  // No need for hocus pocus and poorman until site is installed.
  if (variable_get('install_task') != 'done') {
    return;
  }
  $name = 'cron_last';
  if ($value = db_query("SELECT value FROM {variable} WHERE name = :name", array(
    ':name' => $name,
  ))
    ->fetchField()) {
    $value = unserialize($value);
  }
  global $conf;
  $conf['cron_last'] = $value;
  ultimate_cron_trigger_poorman();
}

/**
 * Launch poorman cron if it's time to do so.
 */
function ultimate_cron_trigger_poorman() {

  // Launch poormans cron if applicable
  if (variable_get('ultimate_cron_poorman', ULTIMATE_CRON_POORMAN) && !_ultimate_cron_incompatible_modules()) {
    $last = variable_get('cron_last', 0);
    $last = floor($last / 60) * 60;
    $time = time();
    $time = floor($time / 60) * 60;

    // Don't attempt, if already run within last minute
    if ($last < $time) {
      ultimate_cron_launch_poorman();
    }
  }
}

/**
 * Launch the poormans cron background process.
 */
function ultimate_cron_launch_poorman() {
  $handle = 'ultimate_cron_poorman';
  if ($process = background_process_get_process($handle)) {
    if ($process->start + 120 < time()) {

      // Must have timed out or something ... remove it!
      if (background_process_remove_process($handle, $process->start)) {
        $process = NULL;
      }
    }
  }
  if (!$process) {
    $process = new BackgroundProcess($handle);

    // Because anyone can launch poormans cron, run it as anonymous
    $process->uid = 0;
    $process->service_host = 'ultimate_cron_poorman';
    $result = $process
      ->start('_ultimate_cron_poorman');
  }
}

/**
 * Implements hook_background_process_shutdown().
 *
 * Shutdown handler for cronjobs.
 */
function ultimate_cron_background_process_shutdown($process, $shutdown_msg = NULL) {
  $args = func_get_args();
  $record = drupal_static('ultimate_cron_record', FALSE);
  $handle_prefix = variable_get('ultimate_cron_handle_prefix', ULTIMATE_CRON_HANDLE_PREFIX);
  $name = preg_replace('/^' . $handle_prefix . '/', '', $process->handle);
  if (!empty($name) && $name != $process->handle) {
    static $has_run = array();
    if (!empty($has_run[$name])) {
      return;
    }
    $has_run[$name] = TRUE;

    // Record end time
    $end = microtime(TRUE);
    if ($record) {

      // Get drupal messages
      $messages = drupal_get_messages(NULL, TRUE);
      $messages['status'] = empty($messages['status']) ? array() : $messages['status'];
      $messages['warning'] = empty($messages['warning']) ? array() : $messages['warning'];
      $messages['error'] = empty($messages['error']) ? array() : $messages['error'];
      foreach ($messages['status'] as $message) {
        ultimate_cron_record_log($message);
      }
      foreach ($messages['warning'] as $message) {
        ultimate_cron_record_log($message, FALSE, WATCHDOG_WARNING);
      }
      foreach ($messages['error'] as $message) {
        ultimate_cron_record_log($message, FALSE, WATCHDOG_ERROR);
      }

      // Get error messages
      $error = error_get_last();
      if ($error) {
        $message = $error['message'] . ' (line ' . $error['line'] . ' of ' . $error['file'] . ').' . "\n";
        $severity = WATCHDOG_INFO;
        if ($error['type'] && (E_NOTICE || E_USER_NOTICE || E_USER_WARNING)) {
          $severity = WATCHDOG_NOTICE;
        }
        if ($error['type'] && (E_WARNING || E_CORE_WARNING || E_USER_WARNING)) {
          $severity = WATCHDOG_WARNING;
        }
        if ($error['type'] && (E_ERROR || E_CORE_ERROR || E_USER_ERROR || E_RECOVERABLE_ERROR)) {
          $severity = WATCHDOG_ERROR;
        }
        ultimate_cron_record_log($message, FALSE, $severity);
      }
    }
    if ($shutdown_msg) {
      ultimate_cron_record_log($shutdown_msg, FALSE, WATCHDOG_ERROR);
    }
    $log = drupal_static('ultimate_cron_record_log', array(
      'msg' => '',
      'severity' => -1,
    ));
    $severity = $log['severity'];
    $msg = $log['msg'];
    $result = $severity < 0 || $severity >= WATCHDOG_INFO ? 1 : 0;

    // log results here ...
    $object = (object) array(
      'name' => $name,
      'start_stamp' => $process->start,
      'end_stamp' => $end,
      'service_host' => $process->service_host,
      'exec_status' => $result,
      'severity' => $severity,
      'msg' => trim($msg),
    );
    $old_db = db_set_active('background_process');
    drupal_write_record('ultimate_cron_log', $object);
    db_set_active($old_db);
    $object->formatted['start_stamp'] = format_date((int) $object->start_stamp, 'custom', 'Y-m-d H:i:s');
    $object->formatted['end_stamp'] = format_date((int) $object->end_stamp, 'custom', 'Y-m-d H:i:s');
    $object->formatted['duration'] = gmdate('H:i:s', (int) ($object->end_stamp - $object->start_stamp));
    $object->formatted['severity'] = $object->severity < 0 ? 'success' : ($object->severity >= WATCHDOG_NOTICE ? 'info' : ($object->severity >= WATCHDOG_WARNING ? 'warning' : 'error'));
    $object->formatted['executeURL'] = url('admin/ultimate-cron/service/start/' . $object->name, array(
      'query' => array(
        'destination' => 'admin/config/system/cron',
      ),
    ));
    $object->formatted['msg'] = strip_tags(html_entity_decode($object->msg, ENT_QUOTES));
    if (module_exists('nodejs')) {
      $message = (object) array(
        'channel' => 'ultimate_cron',
        'data' => (object) array(
          'action' => 'log',
          'log' => $object,
        ),
        'callback' => 'nodejsUltimateCron',
      );
      nodejs_send_content_channel_message($message);
    }
  }
}

// ---------- FIXUPS FOR CORE  ----------

/**
 * Implements hook_menu_alter().
 *
 * Steal the run-cron, so when you "run cron manually" from the status-reports
 * page the ultimate_cron cron handler is run.
 */
function ultimate_cron_menu_alter(&$items) {
  if (_ultimate_cron_incompatible_modules()) {
    return;
  }
  $items['admin/config/system/cron'] = array(
    'title' => 'Cron',
    'description' => 'View and manage cron table',
    'page callback' => 'ultimate_cron_view_page',
    'access arguments' => array(
      'administer ultimate cron',
    ),
    'module' => 'ultimate_cron',
    'file' => 'ultimate_cron.admin.inc',
  );
  $items['admin/config/system/cron/overview'] = array(
    'title' => 'List',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -10,
  );
  $steal =& $items['admin/reports/status/run-cron'];
  $steal['page callback'] = 'ultimate_cron_run_cron';
  $steal['page arguments'] = array();
  $steal['module'] = 'ultimate_cron';
  $steal['file'] = 'ultimate_cron.admin.inc';
}

/**
 * Implements hook_cron_alter().
 * Add better description to core modules.
 */
function ultimate_cron_cron_alter(&$hooks) {
  $update['dblog_cron']['description'] = t('Remove expired log messages and flood control events');
  $update['field_cron']['description'] = t('Purges deleted Field API data');
  $update['filter_cron']['description'] = t('Expire outdated filter cache entries');
  $update['node_cron']['description'] = t('Mark old nodes as read');
  $update['search_cron']['description'] = t('Update indexes');
  $update['system_cron']['description'] = t('Cleanup (batch, flood, temp-files, etc.)');
  $update['aggregator_cron']['description'] = t('Refresh feeds');
  $update['openid_cron']['description'] = t('Remove expired nonces from the database');
  $update['ping_cron']['description'] = t('Notify remote sites');
  $update['poll_cron']['description'] = t('Close expired polls');
  $update['statistics_cron']['description'] = t('Reset counts and clean up');
  $update['trigger_cron']['description'] = t('Run actions for cron triggers');
  $update['tracker_cron']['description'] = t('Update tracker index');
  $update['update_cron']['description'] = t('Check system for updates');
  $update['ultimate_cron_cleanup_log']['configure'] = 'admin/config/system/cron/settings';
  $update['dblog_cron']['configure'] = 'admin/config/development/logging';
  foreach ($update as $name => $data) {
    if (isset($hooks[$name])) {
      foreach ($data as $key => $value) {
        $hooks[$name][$key] = $value;
      }
    }
  }
}

// ---------- HELPER FUNCTIONS ----------

/**
 * Set current hook being processed
 *
 * @param $hook
 * @return
 *   Current hook
 */
function ultimate_cron_set_current_hook($hook = NULL) {
  static $current_hook;
  if ($hook) {
    $current_hook = $hook;
  }
  return $current_hook;
}

/**
 * Get current hook being processed
 *
 * @return
 *   Current hook
 */
function ultimate_cron_get_current_hook() {
  return ultimate_cron_set_current_hook();
}

/**
 * The actual poorman function
 * @return type
 */
function _ultimate_cron_poorman() {
  if (!variable_get('ultimate_cron_poorman', ULTIMATE_CRON_POORMAN) || _ultimate_cron_incompatible_modules()) {
    return;
  }

  // Restart when done
  background_process_keepalive();

  // Derive current minute
  $time = time();
  $time = floor($time / 60) * 60;

  // Run the cron
  ultimate_cron_cron_run(TRUE);

  // Wait until end of "current" minute
  $wait = $time + 60 - time();
  if ($wait > 0 && $wait <= 60) {
    sleep($wait);
  }
}

/**
 * Clean up log entries.
 */
function ultimate_cron_cleanup_log() {
  do {
    $result = db_query_range("SELECT lid FROM {ultimate_cron_log} WHERE start_stamp < :start", 0, 1000, array(
      ':start' => time() - variable_get('ultimate_cron_cleanup_log', ULTIMATE_CRON_CLEANUP_LOG),
    ));
    $lids = array();
    while ($row = $result
      ->fetchObject()) {
      $lids[] = $row->lid;
    }
    if (!empty($lids)) {
      db_query("DELETE FROM {ultimate_cron_log} WHERE lid IN (:lids)", array(
        ':lids' => $lids,
      ));
    }
  } while (!empty($lids));
}

/**
 * Run a cron hook.
 * Launches the cron job in a background process
 *
 * @param $name
 * @param $hook
 * @return mixed
 *   Connections file handle on success.
 */
function ultimate_cron_run_hook($name, $hook) {

  // Run the job in background
  $result = NULL;
  $handle_prefix = variable_get('ultimate_cron_handle_prefix', ULTIMATE_CRON_HANDLE_PREFIX);
  $handle = $handle_prefix . $name;
  $process = new BackgroundProcess($handle);

  // Always run cron job as anonymous user
  $process->uid = 0;

  // Determine service group
  $process->service_group = empty($hook['settings']['service_group']) ? variable_get('ultimate_cron_service_group', ULTIMATE_CRON_SERVICE_GROUP) : $hook['settings']['service_group'];
  $hook['timestamp'] = time();
  unset($hook['log']['msg']);
  $result = $process
    ->start('_ultimate_cron_run_hook', array(
    $name,
    $hook,
  ));
  return $result ? $process->connection : $result;
}
function ultimate_cron_run_hook_cli($name, $hook) {

  // Run the job in background
  $result = NULL;
  $handle_prefix = variable_get('ultimate_cron_handle_prefix', ULTIMATE_CRON_HANDLE_PREFIX);
  $handle = $handle_prefix . $name;
  $process = new BackgroundProcess($handle);

  // Always run cron job as anonymous user
  $process->uid = 0;
  $hook['timestamp'] = time();
  if ($process
    ->lock()) {
    try {
      $process_obj = background_process_get_process($handle);
      $process->start = $process_obj->start;
      if (function_exists('background_process_update_status')) {
        background_process_update_status($handle, BACKGROUND_PROCESS_STATUS_RUNNING);
      }
      else {
        db_update('background_process')
          ->fields(array(
          'exec_status' => BACKGROUND_PROCESS_STATUS_RUNNING,
        ))
          ->condition('handle', $handle)
          ->execute();
      }
      $old_handle = background_process_current_handle();
      background_process_current_handle($handle);
      _ultimate_cron_run_hook($name, $hook);
      module_invoke_all('background_process_shutdown', $process);
      background_process_current_handle($old_handle);
      background_process_remove_process($handle, $process->start);
      return TRUE;
    } catch (Exception $e) {
      module_invoke_all('background_process_shutdown', $process, (string) $e);
      return NULL;
    }
  }
  return FALSE;
}

/**
 * This is the function that is launched into a background process.
 * It runs the cron job and does housekeeping, pre/post execute hooks, etc.
 *
 * @param $module
 *   Module containing function.
 * @param $name
 *   Function to call.
 * @return boolean
 *   TRUE on success, FALSE on failure.
 */
function _ultimate_cron_run_hook($name, $hook) {
  @set_time_limit(variable_get('ultimate_cron_max_execution_time', ULTIMATE_CRON_MAX_EXECUTION_TIME));
  drupal_save_session(FALSE);

  // Load current process
  $process = background_process_get_process(background_process_current_handle());
  $record =& drupal_static('ultimate_cron_record', FALSE);
  $record = TRUE;
  ultimate_cron_record_log(NULL, TRUE);

  // Load log if not present
  if (!isset($hook['log'])) {
    $hook['log'] = ultimate_cron_get_log($name);
  }
  $time = time();
  if (empty($hook['skip_catch_up']) && !ultimate_cron_hook_should_run($hook)) {

    // Hook started too late!
    watchdog('ultimate_cron', '%function skipped. Invoked at %invoke, but did not start until %start', array(
      '%function' => $name,
      '%invoke' => format_date($hook['timestamp'], 'custom', 'Y-m-d H:i:s'),
      '%start' => format_date($time, 'custom', 'Y-m-d H:i:s'),
    ), WATCHDOG_ERROR);
    ultimate_cron_background_process_shutdown($process, NULL);
    return FALSE;
  }

  // Let other modules do stuff before execution, if they need to.
  module_invoke_all('cron_pre_execute', $name, $hook);
  module_invoke_all('cron_pre_execute_' . $name, $hook);
  if (!empty($hook['file'])) {
    include_once $hook['file'];
  }
  $callback = $hook['callback'];
  ultimate_cron_set_current_hook($hook);
  if (is_callable($callback)) {
    call_user_func($callback);
  }
  else {
    module_invoke($hook['module'], 'cronapi', 'execute', $name, $hook);
  }
  ultimate_cron_background_process_shutdown($process, NULL);

  // Let other modules do stuff before execution, if they need to.
  module_invoke_all('cron_post_execute', $name, $hook);
  module_invoke_all('cron_post_execute_' . $name, $hook);
  return TRUE;
}

/**
 * Get a list of functions that should be run now.
 *
 * @param $hooks
 *   Array of cron hooks to check.
 * @return array
 *   Functions to run now.
 */
function ultimate_cron_get_schedule($hooks) {

  // Create list of scheduled functions
  $schedule = array();
  foreach ($hooks as $name => &$hook) {
    ultimate_cron_load_hook_data($hook);

    // Store last run in hook for sorting purposes
    $last_run = isset($hook['log']['start']) ? $hook['log']['start'] : 0;
    $hook['last_run'] = $last_run;
    if (ultimate_cron_hook_should_run($hook)) {
      $schedule[$name] = $hook;
    }
  }

  // Sort by last run time
  uasort($schedule, '_ultimate_cron_sort_schedule');

  // Allow other to manipulate the schedule
  drupal_alter('cron_schedule', $schedule);
  return $schedule;
}

/**
 * Populate hook array with settings and log data
 *
 * @param type $hook
 */
function ultimate_cron_load_hook_data(&$hook) {

  // Get settings
  $hook['settings'] = ultimate_cron_get_settings($hook['function']) + $hook['settings'];

  // Get log, used for checking last start time
  $hook['log'] = ultimate_cron_get_log($hook['function']);
}

/**
 * Check if a hook should be run now.
 *
 * @param array $hook
 * @return boolean
 */
function ultimate_cron_hook_should_run($hook) {

  // Is it enabled?
  if (empty($hook['settings']['enabled'])) {
    return FALSE;
  }
  $last_run = isset($hook['log']['start']) ? $hook['log']['start'] : 0;
  return ultimate_cron_should_run($hook['settings']['rules'], $last_run, time(), $hook['settings']['catch_up'], $hook['delta']);
}

/**
 * Sort callback for ordering schedule.
 *
 * @param type $a
 * @param type $b
 * @return type
 */
function _ultimate_cron_sort_schedule($a, $b) {
  return $a['last_run'] == $b['last_run'] ? 0 : ($a['last_run'] < $b['last_run'] ? -1 : 1);
}

/**
 * Get cron hooks available.
 *
 * @return array
 *   List of modules.
 */
function ultimate_cron_get_hooks() {
  static $hooks = NULL;
  if (isset($hooks)) {
    return $hooks;
  }
  $hooks = array();
  $delta = 0;

  // Generate list of hooks
  $modules = module_list();
  foreach ($modules as $module) {
    $file = drupal_get_path('module', $module) . '/' . $module . '.info';
    $info = drupal_parse_info_file($file);
    foreach (ultimate_cron_easy_hooks() as $hook => $description) {
      if (module_hook($module, $hook)) {
        $name = $module . '_' . $hook;
        $hooks[$name]['description'] = $description;
        $hooks[$name]['module'] = $module;
        $hooks[$name]['configure'] = isset($info['configure']) ? $info['configure'] : '';
        $hooks[$name]['settings'] = ultimate_cron_get_default_settings($module, $name, ultimate_cron_easy_hooks_rule($hook));
      }
    }
    if ($cronapi = module_invoke($module, 'cronapi', 'list')) {
      foreach ($cronapi as $name => $description) {
        $hooks[$name]['description'] = $description;
        $hooks[$name]['module'] = $module;
        $hooks[$name]['settings'] = ultimate_cron_get_default_settings($module, $name, ultimate_cron_easy_hooks_rule('cron'));
        $hooks[$name]['configure'] = module_invoke($module, 'cronapi', 'configure', $name);
      }
    }
  }
  foreach ($hooks as $name => &$hook) {
    $hook['callback'] = $hook['function'] = $name;
    $hook['background_process'] = array();
    $hook['delta'] = $delta++;
  }

  // Remove ourselves from the list
  unset($hooks['ultimate_cron_cron']);

  // Allow other to manipulate the hook list
  drupal_alter('cron', $hooks);
  return $hooks;
}

/**
 * Get default settings for job.
 *
 * @param type $module
 * @param type $name
 * @return array
 */
function ultimate_cron_get_default_settings($module, $name, $default_rule) {
  $conf = module_invoke($module, 'cronapi', 'settings', $name);
  if (!is_array($conf)) {
    $conf = array();
  }
  $rule = module_invoke($module, 'cronapi', 'rule', $name);
  if (empty($conf['rules']) && !empty($rule)) {
    $conf['rules'] = is_array($rule) ? $rule : array(
      $rule,
    );
  }
  $conf += _ultimate_cron_default_settings($default_rule);
  return $conf;
}

/**
 * Get settings for a function.
 *
 * @param $name
 * @return array
 *   Settings for function
 */
function ultimate_cron_get_settings($name) {
  $settings = array();
  if (module_exists('ctools')) {
    ctools_include('export');
    $function = ctools_export_crud_load('ultimate_cron', $name);
    if ($function) {
      $settings = (array) $function->settings;
    }
  }
  else {
    $function = db_query("SELECT settings FROM {ultimate_cron} WHERE name = :name", array(
      ':name' => $name,
    ))
      ->fetchObject();
    if (!empty($function) && !empty($function->settings)) {
      $settings = (array) unserialize($function->settings);
    }
  }
  if (empty($settings['catch_up'])) {
    unset($settings['catch_up']);
  }
  return $settings;
}

/**
 * CRUD save. Also used for ctools integration.
 * @param object $object
 *   object to be saved ->name containing unique machine name.
 * @return boolean
 *   result of query.
 */
function ultimate_cron_crud_save($object) {
  return db_merge('ultimate_cron')
    ->key(array(
    'name' => $object->name,
  ))
    ->fields(array(
    'settings' => serialize($object->settings),
  ))
    ->execute();
}

/**
 * Set settings for a function.
 *
 * @param $name
 *   Function to set settings for.
 * @param $settings
 *   Settings data
 * @return boolean
 *   TRUE on success, FALSE on failure.
 */
function ultimate_cron_set_settings($name, $settings) {
  if (module_exists('ctools')) {
    ctools_include('export');
    $function = ctools_export_crud_new('ultimate_cron');
    $function->name = $name;
    $function->settings = $settings;
    return ctools_export_crud_save('ultimate_cron', $function);
  }
  else {
    $function = new stdClass();
    $function->name = $name;
    $function->settings = $settings;
    return ultimate_cron_crud_save($function);
  }
}

/**
 * Get latest log line for a function.
 *
 * @param $name
 *   Function to get latest log line for,
 * @return object
 *   Log line.
 */
function ultimate_cron_get_log($name) {
  $log = db_query_range("\n    SELECT l.* FROM {ultimate_cron_log} l\n    WHERE l.name = :name\n    ORDER BY l.start_stamp DESC", 0, 1, array(
    ':name' => $name,
  ))
    ->fetchAssoc();
  if ($log) {
    $log['start'] = $log['start_stamp'];
    $log['status'] = $log['exec_status'];
    $log['end'] = $log['end_stamp'];
  }
  return $log;
}

/**
 * Store watchdog error messages for later use.
 *
 * @staticvar string $log
 * @param $msg
 *   Message to record.
 * @param $reset
 *   Reset recorded message.
 * @return string
 *   Message recorded.
 */
function ultimate_cron_record_log($msg = NULL, $reset = FALSE, $severity = -1) {
  $log =& drupal_static('ultimate_cron_record_log', array());
  if ($reset) {
    $log = array();
  }
  $log += array(
    'msg' => '',
    'severity' => -1,
  );
  if ($msg) {
    $log['msg'] .= "{$msg}\n";
  }
  $log['severity'] = $log['severity'] < 0 || $severity >= 0 && $severity < $log['severity'] ? $severity : $log['severity'];
  return $log['msg'];
}

/**
 * Check if rule is valid.
 *
 * @param $rule
 *   rule to validate.
 * @return
 *   TRUE if valid, FALSE if not.
 */
function ultimate_cron_validate_rule($rule) {
  require_once 'CronRule.class.php';
  $cron = new CronRule($rule);
  if (!$cron
    ->isValid()) {
    return FALSE;
  }
  else {
    return TRUE;
  }
}

/**
 * Check if rule is scheduled to run at a given time.
 *
 * @param $rules
 *   rules to validate.
 * @param $last_run
 *   last time the rule was run.
 * @param $now
 *   time of validation, set to NULL for now.
 * @param $catch_up
 *   run if we missed our time window?
 * @return boolean
 *   TRUE if rule is scheduled to run, FALSE if not.
 */
function ultimate_cron_should_run($rules, $job_last_ran, $now = NULL, $catch_up = 0, $offset = 0) {
  $now = is_null($now) ? time() : $now;
  require_once 'CronRule.class.php';
  $cron = new CronRule();
  foreach ($rules as $rule) {
    $cron->rule = $rule;
    $cron->offset = $offset;
    $cron_last_ran = $cron
      ->getLastRan($now);
    if ($job_last_ran < $cron_last_ran && $cron_last_ran <= $now) {
      if ($now <= $cron_last_ran + $catch_up) {
        return TRUE;
      }
    }
  }
  return FALSE;
}

/**
 * Get a list of the "easy-hooks".
 *
 * @return array
 *    hooks (hook_name => hook_description).
 */
function ultimate_cron_easy_hooks() {
  return array(
    'cron' => 'Default cron handler',
    'hourly' => 'Hourly',
    'daily' => 'Daily',
    'weekly' => 'Weekly',
    'monthly' => 'Monthly',
    'yearly' => 'Yearly',
  );
}

/**
 * Get rule(s) for easy hook(s)
 *
 * @param $hook
 *   Hook to get rule for (optional).
 * @return mixed
 *   Rule for $hook if specified, otherwise all rules for all easy hooks.
 */
function ultimate_cron_easy_hooks_rule($hook = NULL) {
  $rules = array(
    'cron' => variable_get('ultimate_cron_rule', ULTIMATE_CRON_RULE),
    'hourly' => ULTIMATE_CRON_HOURLY_RULE,
    'daily' => ULTIMATE_CRON_DAILY_RULE,
    'weekly' => ULTIMATE_CRON_WEEKLY_RULE,
    'monthly' => ULTIMATE_CRON_MONTHLY_RULE,
    'yearly' => ULTIMATE_CRON_YEARLY_RULE,
  );
  return isset($rules[$hook]) ? $rules[$hook] : variable_get('ultimate_cron_rule', ULTIMATE_CRON_RULE);
}

/**
 * Get module name
 * @param $module
 * @return string
 *   Name of module
 */
function ultimate_cron_module_name($module) {
  $file = drupal_get_path('module', $module) . '/' . $module . '.info';
  $info = drupal_parse_info_file($file);
  return $info['name'] ? $info['name'] : $module;
}

/**
 * Load all cronjob settings and processes.
 *
 * @return array
 *   Array of cronjobs and their data.
 */
function _ultimate_cron_preload_cron_data() {
  $handle_prefix = variable_get('ultimate_cron_handle_prefix', ULTIMATE_CRON_HANDLE_PREFIX);
  if (module_exists('ctools')) {
    ctools_include('export');
    $functions = ctools_export_crud_load_all('ultimate_cron');
  }
  else {
    $functions = db_select('ultimate_cron', 'u')
      ->fields('u', array(
      'name',
      'settings',
    ))
      ->execute()
      ->fetchAllAssoc('name', PDO::FETCH_ASSOC);
    foreach ($functions as &$function) {
      $function = (object) $function;
      if (!empty($function->settings)) {
        $function->settings = unserialize($function->settings);
      }
    }
  }
  $hooks = ultimate_cron_get_hooks();
  if (function_exists('background_process_update_status')) {
    $query = db_select('background_process', 'b')
      ->fields('b', array(
      'handle',
      'service_host',
    ))
      ->condition('handle', $handle_prefix . '%', 'LIKE');
    $query
      ->addField('b', 'start_stamp', 'start');
    $query
      ->addField('b', 'exec_status', 'status');
    $processes = $query
      ->execute()
      ->fetchAllAssoc('handle', PDO::FETCH_ASSOC);
  }
  else {
    $processes = db_select('background_process', 'b')
      ->fields('b', array(
      'handle',
      'service_host',
      'start',
      'status',
    ))
      ->condition('handle', $handle_prefix . '%', 'LIKE')
      ->execute()
      ->fetchAllAssoc('handle', PDO::FETCH_ASSOC);
  }
  $data = array();
  foreach ($hooks as $name => $hook) {
    $settings = empty($functions[$name]->settings) ? array() : $functions[$name]->settings;
    $settings += $hook['settings'];
    $handle = $handle_prefix . $name;
    $data[$name] = array(
      'settings' => $settings,
      'background_process' => empty($processes[$handle]) ? NULL : (object) $processes[$handle],
    );
  }
  return $data;
}

/**
 * Return a list of modules that are incompatible with Ultimate Cron
 */
function _ultimate_cron_incompatible_modules() {
  static $modules = NULL;
  if (isset($modules)) {
    return $modules;
  }
  $modules = array();
  $candidates = array(
    'parallel_cron',
  );
  foreach ($candidates as $module) {
    if (module_exists($module)) {
      $modules[$module] = ultimate_cron_module_name($module);
    }
  }
  return $modules;
}

/**
 * Get service hosts defined in the system.
 */
function ultimate_cron_get_service_groups() {
  if (function_exists('background_process_get_service_groups')) {
    return background_process_get_service_groups();
  }

  // Fallback for setups that havent upgraded Background Process.
  // We have this to avoid upgrade dependencies or majer version bump.
  $service_groups = variable_get('background_process_service_groups', array());
  $service_groups += array(
    'default' => array(
      'hosts' => array(
        variable_get('background_process_default_service_host', 'default'),
      ),
    ),
  );
  foreach ($service_groups as &$service_group) {
    $service_group += array(
      'method' => 'background_process_service_group_random',
    );
  }
  return $service_groups;
}

/**
 * Smelly code; $default_rule determines if we should populate ...
 */
function _ultimate_cron_default_settings($default_rule = NULL) {
  return array(
    'enabled' => TRUE,
    'rules' => $default_rule ? array(
      $default_rule,
    ) : array(),
    'catch_up' => $default_rule ? variable_get('ultimate_cron_catch_up', ULTIMATE_CRON_CATCH_UP) : '',
    'queue_lease_time' => '',
    'queue_polling_throttle' => '',
  );
}

Functions

Namesort descending Description
ultimate_cron_background_process_message_alter Implements hook_background_process_message_alter().
ultimate_cron_background_process_shutdown Implements hook_background_process_shutdown().
ultimate_cron_cleanup_log Clean up log entries.
ultimate_cron_cronapi Implements hook_cronapi().
ultimate_cron_cron_alter Implements hook_cron_alter(). Add better description to core modules.
ultimate_cron_cron_queue_info Implements hook_cron_queue_info(). Used for code injection in order to hijack cron runs.
ultimate_cron_cron_run The cron handler takes over the normal Drupal cron handler and runs the normal hook_cron() plus the hook_cronapi().
ultimate_cron_crud_save CRUD save. Also used for ctools integration.
ultimate_cron_easy_hooks Get a list of the "easy-hooks".
ultimate_cron_easy_hooks_rule Get rule(s) for easy hook(s)
ultimate_cron_get_current_hook Get current hook being processed
ultimate_cron_get_default_settings Get default settings for job.
ultimate_cron_get_hooks Get cron hooks available.
ultimate_cron_get_log Get latest log line for a function.
ultimate_cron_get_schedule Get a list of functions that should be run now.
ultimate_cron_get_service_groups Get service hosts defined in the system.
ultimate_cron_get_settings Get settings for a function.
ultimate_cron_help Implements hook_help().
ultimate_cron_hook_should_run Check if a hook should be run now.
ultimate_cron_init Implements hook_init().
ultimate_cron_launch_poorman Launch the poormans cron background process.
ultimate_cron_load_hook_data Populate hook array with settings and log data
ultimate_cron_menu Implements hook_menu().
ultimate_cron_menu_alter Implements hook_menu_alter().
ultimate_cron_module_name Get module name
ultimate_cron_permission Implements hook_permission().
ultimate_cron_progress_message_alter Implements hook_progress_message_alter().
ultimate_cron_record_log Store watchdog error messages for later use.
ultimate_cron_run_hook Run a cron hook. Launches the cron job in a background process
ultimate_cron_run_hook_cli
ultimate_cron_set_current_hook Set current hook being processed
ultimate_cron_set_settings Set settings for a function.
ultimate_cron_should_run Check if rule is scheduled to run at a given time.
ultimate_cron_theme_registry_alter Implements hook_theme_registry_alter().
ultimate_cron_trigger_poorman Launch poorman cron if it's time to do so.
ultimate_cron_validate_rule Check if rule is valid.
ultimate_cron_watchdog Implements hook_watchdog().
_ultimate_cron_default_settings Smelly code; $default_rule determines if we should populate ...
_ultimate_cron_incompatible_modules Return a list of modules that are incompatible with Ultimate Cron
_ultimate_cron_poorman The actual poorman function
_ultimate_cron_preload_cron_data Load all cronjob settings and processes.
_ultimate_cron_run_hook This is the function that is launched into a background process. It runs the cron job and does housekeeping, pre/post execute hooks, etc.
_ultimate_cron_sort_schedule Sort callback for ordering schedule.

Constants

Namesort descending Description
ULTIMATE_CRON_CATCH_UP Default catch up time for Ultimate Cron.
ULTIMATE_CRON_CLEANUP_LOG Default clean up time for log entries (30 days).
ULTIMATE_CRON_DAILY_RULE Default rule for easy hook "daily".
ULTIMATE_CRON_HANDLE_PREFIX Default handle prefix for background processes.
ULTIMATE_CRON_HOURLY_RULE Default rule for easy hook "hourly".
ULTIMATE_CRON_LAUNCH_WINDOW Time in seconds to spend on launcing cron jobs.
ULTIMATE_CRON_MAX_EXECUTION_TIME Default max execution time for Ultimate Cron.
ULTIMATE_CRON_MONTHLY_RULE Default rule for easy hook "monthly".
ULTIMATE_CRON_POORMAN Default setting for poorman.
ULTIMATE_CRON_QUEUE_LEASE_TIME Default lease time for Ultimate Cron queues.
ULTIMATE_CRON_QUEUE_POLLING_LATENCY Default queue polling latency.
ULTIMATE_CRON_RULE Default rule.
ULTIMATE_CRON_SERVICE_GROUP Time in seconds to spend on launcing cron jobs.
ULTIMATE_CRON_SIMULTANEOUS_CONNECTIONS Maximum number of simultaneous connections.
ULTIMATE_CRON_WEEKLY_RULE Default rule for easy hook "weekly".
ULTIMATE_CRON_YEARLY_RULE Default rule for easy hook "yearly".