summaryrefslogtreecommitdiff
path: root/modules/system/system.module
diff options
context:
space:
mode:
Diffstat (limited to 'modules/system/system.module')
-rw-r--r--modules/system/system.module115
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>';
+}
+