Index: poormanscron.admin.inc =================================================================== RCS file: poormanscron.admin.inc diff -N poormanscron.admin.inc --- poormanscron.admin.inc 27 Apr 2008 09:40:29 -0000 1.1.2.1 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,35 +0,0 @@ - 'fieldset', '#title' => t('Time intervals')); - $form['time_intervals']['poormanscron_interval'] = array( - '#type' => 'textfield', '#title' => t('Cron runs interval'), - '#default_value' => variable_get('poormanscron_interval', 60), - '#size' => 5, '#maxlength' => 10, - '#description' => t('Minimum number of minutes between cron runs. Cron will actually execute during the first page request after the interval has elapsed.') - ); - $form['time_intervals']['poormanscron_retry_interval'] = array( - '#type' => 'textfield', '#title' => t('Retry interval'), - '#default_value' => variable_get('poormanscron_retry_interval', 10), - '#size' => 5, '#maxlength' => 10, - '#description' => t('The number of minutes to wait after a cron run error before retrying.') - ); - - $form['logging'] = array('#type' => 'fieldset', '#title' => t('Logging')); - $form['logging']['poormanscron_log_cron_runs'] = array( - '#type' => 'select', '#title' => t('Log successful cron runs'), - '#default_value' => variable_get('poormanscron_log_cron_runs', 1), - '#options' => array('1' => t('Yes'), '0' => t('No')), - '#description' => t('If you want to log successful cron runs to the Drupal watchdog, say Yes here. If those messages annoy you, disable them by selecting No.') - ); - return system_settings_form($form); -} Index: poormanscron.install =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/poormanscron/Attic/poormanscron.install,v retrieving revision 1.1.2.1 diff -u -p -r1.1.2.1 poormanscron.install --- poormanscron.install 11 Feb 2008 07:28:14 -0000 1.1.2.1 +++ poormanscron.install 27 Sep 2009 21:49:23 -0000 @@ -5,6 +5,15 @@ * Implementation of hook_uninstall(). */ function poormanscron_uninstall() { - db_query("DELETE FROM {variable} WHERE name LIKE 'poormanscron_%'"); - cache_clear_all('variables', 'cache'); + variable_del('poormanscron_interval'); + variable_del('poormanscron_retry_interval'); + variable_del('poormanscron_log_cron_runs'); +} + +function poormanscron_update_6200() { + $interval = variable_get('poormanscron_interval', 60) * 60; + variable_set('cron_safe_threshold', max($interval, 3600)); + variable_del('poormanscron_interval'); + variable_del('poormanscron_retry_interval'); + variable_del('poormanscron_log_cron_runs'); } Index: poormanscron.js =================================================================== RCS file: poormanscron.js diff -N poormanscron.js --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ poormanscron.js 27 Sep 2009 21:49:23 -0000 @@ -0,0 +1,15 @@ +// $Id$ + +/** + * Checks to see if the cron should be automatically run. + */ +Drupal.behaviors.cronCheck = function(context) { + if (Drupal.settings.cronCheck || false) { + $('body:not(.cron-check-processed)', context).addClass('cron-check-processed').each(function() { + // Only execute the cron check if its the right time. + if (Math.round(new Date().getTime() / 1000.0) > Drupal.settings.cronCheck) { + $.get(Drupal.settings.basePath + 'poormanscron/run-cron-check'); + } + }); + } +}; Index: poormanscron.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/poormanscron/poormanscron.module,v retrieving revision 1.21.2.2 diff -u -p -r1.21.2.2 poormanscron.module --- poormanscron.module 6 May 2009 05:07:08 -0000 1.21.2.2 +++ poormanscron.module 27 Sep 2009 21:49:23 -0000 @@ -7,88 +7,98 @@ */ /** - * Implementation of hook_help(). + * Implementation of hook_menu(). */ -function poormanscron_help($path, $arg) { - switch ($path) { - case 'admin/help#poormanscron': - return '

'. t('The Poormanscron module runs cron jobs without the need of the cron application.') .'

'; - case 'admin/settings/poormanscron': - return '

'. t('The settings provided here allow you to administer Poormancron.') .'

'; +function poormanscron_menu() { + $items['poormanscron/run-cron-check'] = array( + 'title' => 'Execute cron', + 'page callback' => 'poormanscron_run_cron_check', + 'access callback' => 'poormanscron_run_cron_check_access', + 'type' => MENU_CALLBACK, + ); + return $items; +} + +/** + * Implementation of hook_init(). + */ +function poormanscron_init() { + if (poormanscron_run_cron_check_access()) { + drupal_add_js(drupal_get_path('module', 'poormanscron') . '/poormanscron.js'); + drupal_add_js(array('cronCheck' => variable_get('cron_last', 0) + variable_get('cron_safe_threshold', 10800)), 'setting'); } } /** - * Implementation of hook_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. * - * Checks if poormanscron needs to be run. If this is the case, it invokes - * the cron hooks of all enabled modules, which are executed after - * all HTML is returned to the browser. So the user who kicks off the cron - * jobs should not notice any delay. + * @see poormanscron_run_cron_check() */ -function poormanscron_exit() { +function poormanscron_run_cron_check_access() { + return variable_get('cron_safe_threshold', 10800) > 0; +} - // Calculate when the next poormanscron run is due. - $lastrun = variable_get('poormanscron_lastrun', 0); - $nextrun = $lastrun + 60 * variable_get('poormanscron_interval', 60); - - // If the configured time has passed, start the next poormanscron run. - if (time() > $nextrun) { - - // If this cron run fails to complete, wait a few minutes before retrying. - variable_set('poormanscron_lastrun', - $lastrun + 60 * variable_get('poormanscron_retry_interval', 10)); - - // Get the current Drupal messages. Use drupal_set_message() so that - // the messages aren't deleted in case the cron run fails and - // we don't get a chance to restore them below. - $saved_messages = drupal_set_message(); - - // Invoke the cron hooks of all enabled modules. - if (drupal_cron_run()) { - $message = 'Cron run completed (via poormanscron).'; - } - else { - $message = 'Cron run unsuccessful (via poormanscron).'; - } +/** + * 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 invoked via an AJAX request + * (if the client's browser supports JavaScript). + * + * @see poormanscron_run_cron_check_access() + */ +function poormanscron_run_cron_check() { + //drupal_page_is_cacheable(FALSE); + $_SERVER['REQUEST_METHOD'] = 'POST'; + + $cron_run = FALSE; + $time = time(); + + // 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 ($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); - // Write a message to the logs if the user wants us to do so. - if (variable_get('poormanscron_log_cron_runs', 1) == 1) { - watchdog('cron', $message); + // Release the cron threshold semaphore. + variable_del('cron_threshold_semaphore'); } - - $t = time(); - - // Update the time of the last poormanscron run (this one). - variable_set('poormanscron_lastrun', $t); - - // Delete any messages added during the cron run (and existing prior - // messages). - drupal_get_messages(); - - // Restore any prior messages. - if (isset($saved_messages)) { - foreach ($saved_messages as $type => $types_messages) { - foreach ($types_messages as $message) { - drupal_set_message($message, $type); - } - } + } + 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', 10800); + if (!isset($cron_last) || ($time - $cron_last > $cron_threshold)) { + // Lock cron threshold semaphore. + variable_set('cron_threshold_semaphore', $time); + $cron_run = drupal_cron_run(); + // Release the cron threshold semaphore. + variable_del('cron_threshold_semaphore'); } } + + drupal_json(array('cron_run' => $cron_run)); + exit; } /** - * Implmentation of hook_menu(). + * Implementation of hook_form_FORM_ID_alter(). */ -function poormanscron_menu() { - $items = array(); - $items['admin/settings/poormanscron'] = array( - 'title' => 'Poormanscron', - 'description' => 'A module which runs Drupal cron jobs without the cron application.', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('poormanscron_admin_settings'), - 'access arguments' => array('administer site configuration'), - 'file' => 'poormanscron.admin.inc', +function poormanscron_form_system_site_information_settings_alter(&$form, &$form_state) { + $form['cron_safe_threshold'] = array( + '#type' => 'select', + '#title' => t('Automatically run cron'), + '#default_value' => variable_get('cron_safe_threshold', 10800), + '#options' => array(0 => t('Never')) + drupal_map_assoc(array(3600, 10800, 21600, 43200, 86400, 604800), 'format_interval'), + '#description' => t('When enabled, the site will check whether cron has been run in the configured interval and automatically run it upon the next page request. For more information visit the status report page.', array('@status-report-url' => url('admin/reports/status'))), ); - return $items; + $form['buttons'] += array('#weight' => 30); } Index: poormanscron.test =================================================================== RCS file: poormanscron.test diff -N poormanscron.test --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ poormanscron.test 27 Sep 2009 21:49:23 -0000 @@ -0,0 +1,59 @@ + 'Poormanscron functionality', + 'description' => 'Tests the poormanscron module.', + 'group' => 'Poormanscron', + ); + } + + function setUp() { + parent::setUp('poormanscron'); + $this->admin_user = $this->drupalCreateUser(array('administer site configuration')); + } + + /** + * Ensure that the cron image callback to run it automatically is working. + */ + function testCronThreshold() { + // Ensure cron does not run when the cron threshold is enabled and was + // not passed. + $cron_last = time(); + $cron_safe_threshold = 100; + variable_set('cron_last', $cron_last); + variable_set('cron_safe_threshold', $cron_safe_threshold); + $this->drupalGet(''); + $this->assertRaw('"cronCheck": ' . ($cron_last + $cron_safe_threshold)); + $this->drupalGet('poormanscron/run-cron-check'); + $this->assertTrue($cron_last == variable_get('cron_last', NULL), t('Cron does not run when the cron threshold is not passed.')); + + // Test if cron runs when the cron threshold was passed. + $cron_last = time() - 200; + variable_set('cron_last', $cron_last); + $this->drupalGet(''); + $this->assertRaw('"cronCheck": ' . ($cron_last + $cron_safe_threshold)); + $this->drupalGet('poormanscron/run-cron-check'); + $this->assertTrue($cron_last < variable_get('cron_last', NULL), t('Cron runs when the cron threshold is passed.')); + + // Disable the cron threshold through the interface. + $this->drupalLogin($this->admin_user); + $this->drupalPost('admin/settings/site-information', array('cron_safe_threshold' => 0), t('Save configuration')); + $this->assertText(t('The configuration options have been saved.')); + + // Test if cron does not run when the cron threshold is disabled. + $cron_last = time() - 200; + variable_set('cron_last', $cron_last); + $this->drupalGet(''); + $this->assertNoRaw('cronCheck'); + $this->drupalGet('poormanscron/run-cron-check'); + $this->assertTrue($cron_last == variable_get('cron_last', NULL), t('Cron does not run when the cron threshold is disabled.')); + } +}