? sites/default/files
? sites/default/settings.php
Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.820
diff -u -p -r1.820 common.inc
--- includes/common.inc 8 Nov 2008 20:05:00 -0000 1.820
+++ includes/common.inc 8 Nov 2008 20:45:50 -0000
@@ -2741,44 +2741,195 @@ function drupal_cron_run() {
// Allow execution to continue even if the request gets canceled.
@ignore_user_abort(TRUE);
+ $cron_run_time = variable_get('cron_run_time', 240);
+ $advanced_cron = variable_get('cron_run_advanced', FALSE);
+ $cron_info = array();
+ $cron_run_max_threads = variable_get('cron_run_max_threads', 4);
+
// Increase the maximum execution time.
- @set_time_limit(240);
+ if (!ini_get('safe_mode')) {
+ @set_time_limit($cron_run_time);
+ }
- // Fetch the cron semaphore
+ // Fetch the cron semaphore.
$semaphore = variable_get('cron_semaphore', FALSE);
+ $cron_wait_semaphore = variable_get('cron_wait_semaphore', FALSE);
- if ($semaphore) {
- if (REQUEST_TIME - $semaphore > 3600) {
- // Either cron has been running for more than an hour or the semaphore
- // was not reset due to a database error.
+ // If we enter the cron run w/o a rid but the semephore is set, that means we
+ // are in a 'cron session'. Thus we need to check to see if we need to time
+ // out this cron session.
+ if (($semaphore || $cron_wait_semaphore) && !$_REQUEST['rid']) {
+ if($advanced_cron) {
+ // See if we have been trying to start the crons for an hour.
+ if($cron_wait_semaphore) {
+ if(REQUEST_TIME - (int)$cron_wait_semaphore > 60) {
+ watchdog('cron', t('Cron has been waiting for a previous cron to shutdown for more than an hour and is most likely stuck.'), WATCHDOG_ERROR);
+ variable_del('cron_wait_semaphore');
+ }
+ else {
+ watchdog('cron', t('Attempting to re-run cron while another cron is waiting for cron shutdown.'), WATCHDOG_WARNING);
+ return;
+ }
+ }
+ if($semaphore) {
+ if(REQUEST_TIME - (int)$semaphore > 3600) {
+ watchdog('cron', t('Cron has been trying to start multiple jobs running for more than an hour and is most likely stuck.'), WATCHDOG_ERROR);
+ variable_del('cron_semaphore');
+ }
+ else {
+ // Cron is still running normally.
+ watchdog('cron', t('Attempting to re-run cron while it is already trying to start multiple jobs.'), WATCHDOG_WARNING);
+ return;
+ }
+ }
+ }
+ else if(REQUEST_TIME - $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 cron semaphore
+ // Release cron semaphore.
variable_del('cron_semaphore');
}
else {
// Cron is still running normally.
watchdog('cron', 'Attempting to re-run cron while it is already running.', array(), WATCHDOG_WARNING);
+ return;
}
}
+ elseif ($_REQUEST['rid']) {
+ $rid = $_REQUEST['rid'];
+ $riid = $_REQUEST['riid'];
+ $run_module = $_REQUEST['module'];
+
+ db_query("UPDATE {cron_run_info} SET run_status = %d, run_date = %d WHERE riid = %d", -1, time(), $riid);
+ watchdog('cron', t('Start running cron thread for %module', array('%module' => $run_module)));
+
+ module_invoke($run_module, 'cron');
+ watchdog('cron', t('Finished running cron thread for %module', array('%module' => $run_module)));
+
+ db_query("UPDATE {cron_run_info} SET run_status = %d, run_stop = %d WHERE riid = %d", WATCHDOG_NOTICE, time(), $riid);
+ db_query("UPDATE {cron_runs} SET run_ticks = run_ticks + 1 WHERE rid = %d", $rid);
+ }
else {
- // Register shutdown callback
- register_shutdown_function('drupal_cron_cleanup');
+ // First truncate any old crons.
+ $max_crons = variable_get('cron_run_history', 50);
+ $truncate = db_result(db_query("SELECT COUNT(*) FROM {cron_runs}"));
+
+ if($truncate > $max_crons) {
+ $rs = db_query_range("SELECT rid FROM {cron_runs} ORDER BY rid DESC", $max_crons, $truncate);
+ while($row = db_fetch_object($rs)) {
+ db_query("DELETE FROM {cron_run_info} WHERE rid = %d", $row->rid);
+ db_query("DELETE FROM {cron_runs} WHERE rid = %d", $row->rid);
+ }
+ }
- // Lock cron semaphore
- variable_set('cron_semaphore', REQUEST_TIME);
+ if($advanced_cron) {
+ // First, we need to wait until the other sessions have finished. We will
+ // also time out as needed any cron sessions that a running to long. This
+ // is so we don't over load the system with some errand cron run and we
+ // keep calling a thread for it, thus getting a race condition.
+
+ // So we know we are waiting on a run to finish and we don't stack up
+ //runs.
+ $cron_wait_semaphore = time();
+ variable_set('cron_wait_semaphore', $cron_wait_semaphore);
+ $max_threads = variable_get('cron_max_threads', 4);
+ $module_count = db_result(db_query("SELECT COUNT(*) FROM {cron_run_info} WHERE run_stop = ''"));
+ while($module_count > $max_threads) {
+ watchdog('cron', t('Cron is attempting to wait for a previous cron run to finish. Currently %module_count modules running', array('%module_count' => $module_count)), NULL, 'admin/logs/cron/' . $rid);
+
+ // Ping every 10 seconds.
+ sleep(10);
+ variable_set('cron_wait_semaphore', $cron_wait_semaphore);
+
+ // Check for stuck modules and release them.
+ $stuck_rs = db_query("SELECT * FROM {cron_run_info} WHERE (%d - run_date) > 1000 AND run_stop = ''", time());
+ while($row = db_fetch_object($stuck_rs)) {
+ watchdog('cron', t('%module was not stopped in over an hour had has been marked as completed with errors.', array('%module' => $row->module_name)), WATCHDOG_ERROR, 'admin/logs/cron/' . $row->rid);
+ db_query("UPDATE {cron_run_info} SET run_stop = %d, run_status = %d WHERE riid = %d", time(), WATCHDOG_ERROR, $row->riid);
+ }
+ // Ping that this session is still running and update the module count.
+ $module_count = db_result(db_query("SELECT COUNT(*) FROM {cron_run_info} WHERE run_stop = ''"));
+ }
+ }
+ // Register shutdown callback.
+ register_shutdown_function('drupal_cron_cleanup');
- // Iterate through the modules calling their cron handlers (if any):
- module_invoke_all('cron');
+ // Lock cron semaphore.
+ $semaphore = time();
+ variable_set('cron_semaphore', $semaphore);
+ if($advanced_cron) {
+ // Release wait lock. Important to to this after locking the session in
+ // general with the semaphore lock.
+ variable_del('cron_wait_semaphore');
+ $winos = eregi("windows", strtolower(php_uname()));
+ $cmd = variable_get('cron_run_command', '');
+ if($cmd == '') {
+ watchdog('cron', t('Cron can not run because you have setup advanced cron without a command'), WATCHDOG_ERROR);
+ return;
+ }
+ global $base_url;
+ $base_path = base_path();
+ $rid = db_next_id("{cron_runs}_rid");
+ db_query("INSERT INTO {cron_runs}(rid, run_date, run_status) VALUES(%d, %d, %d)", $rid, time(), WATCHDOG_WARNING);
+ // Start firing the modules.
+ $modules = module_list();
+ $module_count = 0;
+ foreach($modules as $module) {
+ while($module_count > $cron_run_max_threads) {
+ sleep(5);
+ // Check for stuck modules.
+ $stuck_rs = db_query("SELECT * FROM {cron_run_info} WHERE (%d - run_date) > 3600", time());
+ while($row = db_fetch_object($stuck_rs)) {
+ watchdog('cron', t('%module was started over an hour had has been marked as completed with errors.', array('%module' => $row->module_name)), WATCHDOG_ERROR);
+ db_query("UPDATE {cron_run_info} SET run_stop = %d, run_status = %d WHERE riid = %d", time(), WATCHDOG_ERROR, $row->riid);
+ }
+ // Ping that this session is still running and update the module count.
+ $module_count = db_result(db_query("SELECT COUNT(*) FROM {cron_run_info} WHERE run_stop = '' AND rid = %d", $rid));
+ }
+ // Put some time between firing requests.
+ sleep(1);
+ if(module_hook($module, 'cron')) {
+ $riid = db_next_id("{cron_run_info}_riid");
+ db_query("INSERT INTO {cron_run_info}(riid, rid, module_name, run_status) VALUES(%d, %d, '%s', %d)", $riid, $rid, $module, WATCHDOG_WARNING);
+ $run_cmd = "$cmd \"$base_url/cron.php?rid=$rid&riid=$riid&module=$module\"";
+ if(!$winos) {
+ pclose(popen("$run_cmd & ", "r"));
+ }
+ else {
+ $WshShell = new COM("WScript.Shell");
+ $oExec = $WshShell->Run("cmd /C $run_cmd", 0, false);
+ }
+ $module_count++;
+ }
+ }
+ db_query("UPDATE {cron_runs} SET run_status = %d, run_stop = %d, run_ticks = %d", WATCHDOG_INFO, time(), (-1 * $module_count));
+ }
+ else {
+ // Iterate through the modules calling their cron handlers (if any).
+ db_query("INSERT INTO {cron_runs}(run_date, run_status) VALUES(%d, %d)", time(), WATCHDOG_WARNING);
+ $rid = db_result(db_query("SELECT MAX(rid) FROM {cron_runs}"));
+ db_query("INSERT INTO {cron_run_info}(rid, module_name, run_status, run_date) VALUES(%d, '%s', %d, %d)", $rid, 'system-all-modules', WATCHDOG_WARNING, time());
+ $riid = db_result(db_query("SELECT MAX(riid) FROM {cron_run_info}"));
+ module_invoke_all('cron');
+ db_query("UPDATE {cron_run_info} SET run_status = %d, run_stop = %d WHERE riid = %d", WATCHDOG_NOTICE, time(), $riid);
+ db_query("UPDATE {cron_runs} SET run_status = %d, run_ticks = %d, run_stop = %d WHERE rid = %d",WATCHDOG_INFO, 0, time(), $rid);
+ }
- // Record cron time
- variable_set('cron_last', REQUEST_TIME);
- watchdog('cron', 'Cron run completed.', array(), WATCHDOG_NOTICE);
+ // Record cron time.
+ variable_set('cron_last', time());
+ if($advanced_cron) {
+ watchdog('cron', t('Cron run started %module_count runs.', array('%module_count' => $module_count)), WATCHDOG_NOTICE);
+ }
+ else {
+ watchdog('cron', t('Cron run completed.'), WATCHDOG_NOTICE);
+ }
- // Release cron semaphore
+ // Release cron semaphore.
variable_del('cron_semaphore');
- // Return TRUE so other functions can check if it did run successfully
+ // Return TRUE so other functions can check if it did run successfully.
return TRUE;
}
}
Index: modules/system/system.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.admin.inc,v
retrieving revision 1.102
diff -u -p -r1.102 system.admin.inc
--- modules/system/system.admin.inc 16 Oct 2008 20:23:08 -0000 1.102
+++ modules/system/system.admin.inc 8 Nov 2008 20:45:50 -0000
@@ -2244,3 +2244,178 @@ function theme_system_themes_form($form)
$output .= drupal_render($form);
return $output;
}
+
+/**
+ * Menu callback: provides the cron basic/advanced settings interface.
+ *
+ * A cron run can be setup to run in a "multi-threaded" enviroment.
+ * Each module will have it's own "report" of how it ran, etc.
+ *
+ * @return
+ * The form array.
+ */
+function system_cron_settings($form_values = NULL) {
+ global $base_url;
+ $form['basic_settings'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Basic cron settings'),
+ '#collapsible' => FALSE,
+ );
+ $form['basic_settings']['cron_run_time'] = array(
+ '#type' => 'textfield',
+ '#size' => 5,
+ '#title' => t('Cron run time'),
+ '#description' => t('This is the time in seconds that a cron run is alloted to complete a run. Try increasing this value if you notice that you have a lot of errors of your cron run not finishing.'),
+ '#default_value' => variable_get('cron_run_time', 240),
+ );
+ $history_options = drupal_map_assoc(range(50, 1000, 50));
+ $form['basic_settings']['cron_run_history'] = array(
+ '#type' => 'select',
+ '#title' => t('Cron history'),
+ '#options' => $history_options,
+ '#default_value' => variable_get('cron_run_history', 50),
+ '#description' => t('The number of cron runs you would like to keep. It will delete starting with the oldest cron run.'),
+ );
+ if($base_url == '') {
+ drupal_set_message('warning', t('In order to use advanced cron settings, you must set the $base_url variable in your settings.php file.'));
+ } else {
+ $form['advanced_cron_settings'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Advanced cron settings'),
+ '#collapsible' => FALSE,
+ );
+ $form['advanced_cron_settings']['cron_max_threads'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Max threads'),
+ '#size' => 4,
+ '#description' => t('The maximum number of threads that you would like the run at one time.'),
+ '#default_value' => variable_get('cron_max_threads', 4),
+ );
+ $form['advanced_cron_settings']['cron_run_advanced'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Enable advanced cron runs'),
+ '#description' => t('Check this box to have your cron runs run in a multi-threaded environment. This will also give you more information about each individual modules cron run.'),
+ '#default_value' => variable_get('cron_run_advanced', FALSE),
+ );
+ $form['advanced_cron_settings']['cron_run_command'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Cron run command'),
+ '#description' => t('This is the command you use to run your cron. Use ONLY the command. Example: /usr/bin/lynx -source'),
+ '#default_value' => variable_get('cron_run_command', ""),
+ );
+ }
+ return system_settings_form($form);
+}
+
+/**
+ * Menu callback: cron logs.
+ */
+function system_cron_logs($form_values = NULL) {
+ if(is_numeric(arg(3))) {
+ $rid = arg(3);
+ $cron_run = db_fetch_object(db_query("SELECT cr.rid, cr.run_date, cr.run_status, cr.run_ticks, cr.run_stop, COUNT(riid) modules_ran
+ FROM {cron_runs} cr INNER JOIN {cron_run_info} ci ON cr.rid = ci.rid
+ WHERE cr.rid = %d
+ GROUP BY cr.rid, cr.run_date, cr.run_status, cr.run_ticks, cr.run_stop
+ ", $rid));
+ if(!$cron_run) {
+ drupal_set_message(t('Invalid cron run given'), 'error');
+ drupal_goto('admin/logs/cron');
+ }
+
+ // Icons setup.
+ $icons = array(
+ CRON_RUNNING => theme('image', 'misc/progress.gif', t('running'), t('running')),
+ WATCHDOG_NOTICE => theme('image', 'misc/watchdog-ok.png', t('ok'), t('ok')),
+ WATCHDOG_WARNING => theme('image', 'misc/watchdog-warning.png', t('warning'), t('warning')),
+ WATCHDOG_ERROR => theme('image', 'misc/watchdog-error.png', t('error'), t('error')),
+ );
+
+ // General run information.
+ $form['cron_run_info'] = array('#value' =>
+ t('Run ID') . ': ' . $rid . '
' .
+ t('Run date') . ': ' . format_date($cron_run->run_date, 'large') . '
' .
+ t('Modules ran') . ': ' . $cron_run->modules_ran . '
' .
+ t('Run status') . ': ' . $icons[$cron_run->run_status] . '