diff options
Diffstat (limited to 'modules/system/system.module')
-rw-r--r-- | modules/system/system.module | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/modules/system/system.module b/modules/system/system.module index 5088b4cf8..e768944e3 100644 --- a/modules/system/system.module +++ b/modules/system/system.module @@ -42,6 +42,11 @@ define('DRUPAL_MINIMUM_PGSQL', '8.3'); define('DRUPAL_MAXIMUM_TEMP_FILE_AGE', 21600); /** + * Default interval for automatic cron executions in seconds. + */ +define('DRUPAL_CRON_DEFAULT_THRESHOLD', 10800); + +/** * New users will be set to the default time zone at registration. */ define('DRUPAL_USER_TIMEZONE_DEFAULT', 0); @@ -196,6 +201,9 @@ function system_theme() { 'arguments' => array('version' => NULL), ), 'system_compact_link' => array(), + 'system_run_cron_image' => array( + 'arguments' => array('image_path' => NULL), + ), )); } @@ -496,6 +504,12 @@ function system_menu() { 'access callback' => TRUE, 'type' => MENU_CALLBACK, ); + $items['system/run-cron-image'] = array( + 'title' => 'Execute cron', + 'page callback' => 'system_run_cron_image', + 'access callback' => 'system_run_cron_image_access', + 'type' => MENU_CALLBACK, + ); $items['admin'] = array( 'title' => 'Administer', 'access arguments' => array('access administration pages'), @@ -2968,3 +2982,104 @@ function system_retrieve_file($url, $destination = NULL, $overwrite = TRUE) { return $local; } + +/** + * Implement hook_page_alter(). + */ +function system_page_alter(&$page) { + // Automatic cron runs. + // @see system_run_cron_image() + if (system_run_cron_image_access()) { + $page['page_bottom']['run_cron'] = array( + // Trigger cron run via AJAX. + '#attached_js' => array( + '(function($){ $.get(' . drupal_to_js(url('system/run-cron-image')) . '); })(jQuery);' => array('type' => 'inline', 'scope' => 'header'), + ), + // Trigger cron run for clients not supporting JavaScript (fall-back). + '#markup' => theme('system_run_cron_image', 'system/run-cron-image'), + ); + } +} + +/** + * Menu callback; executes cron via an image callback. + * + * This callback runs cron in a separate HTTP request to prevent "mysterious" + * slow-downs of regular HTTP requests. It is either invoked via an AJAX request + * (if the client's browser supports JavaScript) or by an IMG tag directly in + * the page output (for clients not supporting JavaScript). For the latter case, + * we need to output a transparent 1x1 image, so the browser does not render the + * image's alternate text or a 'missing image placeholder'. The AJAX request + * does not process the returned output. + * + * @see system_page_alter() + * @see theme_system_run_cron_image() + * @see system_run_cron_image_access() + */ +function system_run_cron_image() { + drupal_page_is_cacheable(FALSE); + + // Output a transparent 1x1 image to the browser; required for clients not + // supporting JavaScript. + drupal_set_header('Content-Type', 'image/gif'); + echo "\x47\x49\x46\x38\x39\x61\x1\x0\x1\x0\x80\xff\x0\xc0\xc0\xc0\x0\x0\x0\x21\xf9\x4\x1\x0\x0\x0\x0\x2c\x0\x0\x0\x0\x1\x0\x1\x0\x0\x2\x2\x44\x1\x0\x3b"; + + // Cron threshold semaphore is used to avoid errors every time the image + // callback is displayed when a previous cron is still running. + $threshold_semaphore = variable_get('cron_threshold_semaphore', FALSE); + if ($threshold_semaphore) { + if (REQUEST_TIME - $threshold_semaphore > 3600) { + // Either cron has been running for more than an hour or the semaphore + // was not reset due to a database error. + watchdog('cron', 'Cron has been running for more than an hour and is most likely stuck.', array(), WATCHDOG_ERROR); + + // Release the cron threshold semaphore. + variable_del('cron_threshold_semaphore'); + } + } + else { + // Run cron automatically if it has never run or threshold was crossed. + $cron_last = variable_get('cron_last', NULL); + $cron_threshold = variable_get('cron_safe_threshold', DRUPAL_CRON_DEFAULT_THRESHOLD); + if (!isset($cron_last) || (REQUEST_TIME - $cron_last > $cron_threshold)) { + // Lock cron threshold semaphore. + variable_set('cron_threshold_semaphore', REQUEST_TIME); + drupal_cron_run(); + // Release the cron threshold semaphore. + variable_del('cron_threshold_semaphore'); + } + } + + exit; +} + +/** + * Checks if the feature to automatically run cron is enabled. + * + * Also used as a menu access callback for this feature. + * + * @return + * TRUE if cron threshold is enabled, FALSE otherwise. + * + * @see system_run_cron_image() + * @see system_page_alter() + */ +function system_run_cron_image_access() { + return variable_get('cron_safe_threshold', DRUPAL_CRON_DEFAULT_THRESHOLD) > 0; +} + +/** + * Display image used to run cron automatically. + * + * Renders an image pointing to the automatic cron run menu callback for + * graceful degradation when Javascript is not available. The wrapping NOSCRIPT + * tag ensures that only browsers not supporting JavaScript render the image. + * + * @see system_page_alter() + * @see system_run_cron_image() + * @ingroup themeable + */ +function theme_system_run_cron_image($image_path) { + return '<noscript><div id="system-cron-image">' . theme('image', $image_path, '', '', array(), FALSE) . '</div></noscript>'; +} + |