123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341 |
- <?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 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', TRUE);
- /**
- * 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',
- );
- $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;
- // 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', 'uc:%', '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 = 'uc:' . $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()) {
- fclose($running[$handle->name]);
- unset($running[$handle->name]);
- }
- }
- sleep(1);
- }
- // Close all jobs left
- if ($running) {
- foreach (array_keys($running) as $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;
- 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;
- }
- }
- $function($item->data);
- $queue->deleteItem($item);
- $items++;
- }
- 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) {
- // Only alter Ultimate Cron background process messages
- if (substr($message->data->background_process->handle, 0, 3) !== 'uc:') {
- 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['severity'] <= WATCHDOG_WARNING) {
- $log['variables'] = is_array($log['variables']) ? $log['variables'] : array();
- ultimate_cron_record_log(t($log['message'], $log['variables']));
- }
- }
- /**
- * 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();
- $name = preg_replace('/^uc:/', '', $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);
- $fatal_msg = '';
- if (count(func_get_args()) == 1) {
- $error = error_get_last();
- if ($error) {
- if ($error['type'] & (E_ERROR | E_CORE_ERROR | E_RECOVERABLE_ERROR)) {
- $fatal_msg = $error['message'] . ' (line ' . $error['line'] . ' of ' . $error['file'] . ').' . "\n";
- }
- else {
- $fatal_msg .= t('Died unexpectedly');
- }
- }
- }
- if (is_null($shutdown_msg)) {
- $messages = drupal_get_messages();
- }
- $msg = ultimate_cron_record_log(NULL);
- if ($shutdown_msg) {
- $msg .= $msg ? "\n$shutdown_msg" : $shutdown_msg;
- }
- if (!empty($messages['error'])) {
- $msg .= join("\n", $messages['error']) . "\n";
- }
- $msg .= $fatal_msg;
- // If success, use status messages if any
- $result = empty($msg);
- if ($result && !empty($messages['status'])) {
- $msg = join("\n", $messages['status']);
- }
- // log results here ...
- $object = (object)array(
- 'name' => $name,
- 'start_stamp' => $process->start,
- 'end_stamp' => $end,
- 'service_host' => $process->service_host,
- 'exec_status' => $result,
- '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->exec_status ? 'noerror' : '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 = "uc:" . $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 = "uc:" . $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("
- SELECT l.* FROM {ultimate_cron_log} l
- WHERE l.name = :name
- 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) {
- static $log = '';
- if ($reset) {
- $log = '';
- }
- if ($msg) {
- $log .= "$msg\n";
- }
- return $log;
- }
- /**
- * 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, $last_run, $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;
- $last_ran = $cron->getLastRan($now);
- if ($last_ran > $last_run && $last_ran >= $now - $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() {
- 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', 'uc:%', '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', 'uc:%', '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 = 'uc:' . $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' => '',
- );
- }
|