/** * Runs a scheduled task immediately, given full class name. * * This is faster and more reliable than running cron (running cron won't * work more than once in the same test, for instance). However it is * a little less 'realistic'. * * While the task is running, we suppress mtrace output because it makes * the Behat result look ugly. * * Note: Most of the code relating to running a task is based on * admin/tool/task/cli/schedule_task.php. * * @Given /^I run the scheduled task "(?P<task_name>[^"]+)"$/ * @param string $taskname Name of task e.g. 'mod_whatever\task\do_something' */ public function i_run_the_scheduled_task($taskname) { $task = \core\task\manager::get_scheduled_task($taskname); if (!$task) { throw new DriverException('The "' . $taskname . '" scheduled task does not exist'); } // Do setup for cron task. raise_memory_limit(MEMORY_EXTRA); cron_setup_user(); // Get lock. $cronlockfactory = \core\lock\lock_config::get_lock_factory('cron'); if (!($cronlock = $cronlockfactory->get_lock('core_cron', 10))) { throw new DriverException('Unable to obtain core_cron lock for scheduled task'); } if (!($lock = $cronlockfactory->get_lock('\\' . get_class($task), 10))) { $cronlock->release(); throw new DriverException('Unable to obtain task lock for scheduled task'); } $task->set_lock($lock); if (!$task->is_blocking()) { $cronlock->release(); } else { $task->set_cron_lock($cronlock); } try { // Discard task output as not appropriate for Behat output! ob_start(); $task->execute(); ob_end_clean(); // Mark task complete. \core\task\manager::scheduled_task_complete($task); } catch (Exception $e) { // Mark task failed and throw exception. \core\task\manager::scheduled_task_failed($task); throw new DriverException('The "' . $taskname . '" scheduled task failed', 0, $e); } }
try { get_mailer('buffer'); $task->execute(); if (isset($predbqueries)) { mtrace("... used " . ($DB->perf_get_queries() - $predbqueries) . " dbqueries"); mtrace("... used " . (microtime(1) - $pretime) . " seconds"); } mtrace("Task completed."); \core\task\manager::scheduled_task_complete($task); get_mailer('close'); exit(0); } catch (Exception $e) { if ($DB->is_transaction_started()) { $DB->force_transaction_rollback(); } mtrace("... used " . ($DB->perf_get_queries() - $predbqueries) . " dbqueries"); mtrace("... used " . (microtime(true) - $pretime) . " seconds"); mtrace("Task failed: " . $e->getMessage()); if ($CFG->debugdeveloper) { if (!empty($e->debuginfo)) { mtrace("Debug info:"); mtrace($e->debuginfo); } mtrace("Backtrace:"); mtrace(format_backtrace($e->getTrace(), true)); } \core\task\manager::scheduled_task_failed($task); get_mailer('close'); exit(1); } }
public function test_get_next_scheduled_task() { global $DB; $this->resetAfterTest(true); // Delete all existing scheduled tasks. $DB->delete_records('task_scheduled'); // Add a scheduled task. // A task that runs once per hour. $record = new stdClass(); $record->blocking = true; $record->minute = '0'; $record->hour = '0'; $record->dayofweek = '*'; $record->day = '*'; $record->month = '*'; $record->component = 'test_scheduled_task'; $record->classname = '\core\task\scheduled_test_task'; $DB->insert_record('task_scheduled', $record); // And another one to test failures. $record->classname = '\core\task\scheduled_test2_task'; $DB->insert_record('task_scheduled', $record); // And disabled test. $record->classname = '\core\task\scheduled_test3_task'; $record->disabled = 1; $DB->insert_record('task_scheduled', $record); $now = time(); // Should get handed the first task. $task = \core\task\manager::get_next_scheduled_task($now); $this->assertInstanceOf('\core\task\scheduled_test_task', $task); $task->execute(); \core\task\manager::scheduled_task_complete($task); // Should get handed the second task. $task = \core\task\manager::get_next_scheduled_task($now); $this->assertInstanceOf('\core\task\scheduled_test2_task', $task); $task->execute(); \core\task\manager::scheduled_task_failed($task); // Should not get any task. $task = \core\task\manager::get_next_scheduled_task($now); $this->assertNull($task); // Should get the second task (retry after delay). $task = \core\task\manager::get_next_scheduled_task($now + 120); $this->assertInstanceOf('\core\task\scheduled_test2_task', $task); $task->execute(); \core\task\manager::scheduled_task_complete($task); // Should not get any task. $task = \core\task\manager::get_next_scheduled_task($now); $this->assertNull($task); }
/** * Execute cron tasks */ function cron_run() { global $DB, $CFG, $OUTPUT; if (CLI_MAINTENANCE) { echo "CLI maintenance mode active, cron execution suspended.\n"; exit(1); } if (moodle_needs_upgrading()) { echo "Moodle upgrade pending, cron execution suspended.\n"; exit(1); } require_once $CFG->libdir . '/adminlib.php'; if (!empty($CFG->showcronsql)) { $DB->set_debug(true); } if (!empty($CFG->showcrondebugging)) { set_debugging(DEBUG_DEVELOPER, true); } core_php_time_limit::raise(); $starttime = microtime(); // Increase memory limit raise_memory_limit(MEMORY_EXTRA); // Emulate normal session - we use admin accoutn by default cron_setup_user(); // Start output log $timenow = time(); mtrace("Server Time: " . date('r', $timenow) . "\n\n"); // Run all scheduled tasks. while (!\core\task\manager::static_caches_cleared_since($timenow) && ($task = \core\task\manager::get_next_scheduled_task($timenow))) { mtrace("Execute scheduled task: " . $task->get_name()); cron_trace_time_and_memory(); $predbqueries = null; $predbqueries = $DB->perf_get_queries(); $pretime = microtime(1); try { get_mailer('buffer'); $task->execute(); if ($DB->is_transaction_started()) { throw new coding_exception("Task left transaction open"); } if (isset($predbqueries)) { mtrace("... used " . ($DB->perf_get_queries() - $predbqueries) . " dbqueries"); mtrace("... used " . (microtime(1) - $pretime) . " seconds"); } mtrace("Scheduled task complete: " . $task->get_name()); \core\task\manager::scheduled_task_complete($task); } catch (Exception $e) { if ($DB && $DB->is_transaction_started()) { error_log('Database transaction aborted automatically in ' . get_class($task)); $DB->force_transaction_rollback(); } if (isset($predbqueries)) { mtrace("... used " . ($DB->perf_get_queries() - $predbqueries) . " dbqueries"); mtrace("... used " . (microtime(1) - $pretime) . " seconds"); } mtrace("Scheduled task failed: " . $task->get_name() . "," . $e->getMessage()); if ($CFG->debugdeveloper) { if (!empty($e->debuginfo)) { mtrace("Debug info:"); mtrace($e->debuginfo); } mtrace("Backtrace:"); mtrace(format_backtrace($e->getTrace(), true)); } \core\task\manager::scheduled_task_failed($task); } get_mailer('close'); unset($task); } // Run all adhoc tasks. while (!\core\task\manager::static_caches_cleared_since($timenow) && ($task = \core\task\manager::get_next_adhoc_task($timenow))) { mtrace("Execute adhoc task: " . get_class($task)); cron_trace_time_and_memory(); $predbqueries = null; $predbqueries = $DB->perf_get_queries(); $pretime = microtime(1); try { get_mailer('buffer'); $task->execute(); if ($DB->is_transaction_started()) { throw new coding_exception("Task left transaction open"); } if (isset($predbqueries)) { mtrace("... used " . ($DB->perf_get_queries() - $predbqueries) . " dbqueries"); mtrace("... used " . (microtime(1) - $pretime) . " seconds"); } mtrace("Adhoc task complete: " . get_class($task)); \core\task\manager::adhoc_task_complete($task); } catch (Exception $e) { if ($DB && $DB->is_transaction_started()) { error_log('Database transaction aborted automatically in ' . get_class($task)); $DB->force_transaction_rollback(); } if (isset($predbqueries)) { mtrace("... used " . ($DB->perf_get_queries() - $predbqueries) . " dbqueries"); mtrace("... used " . (microtime(1) - $pretime) . " seconds"); } mtrace("Adhoc task failed: " . get_class($task) . "," . $e->getMessage()); if ($CFG->debugdeveloper) { if (!empty($e->debuginfo)) { mtrace("Debug info:"); mtrace($e->debuginfo); } mtrace("Backtrace:"); mtrace(format_backtrace($e->getTrace(), true)); } \core\task\manager::adhoc_task_failed($task); } get_mailer('close'); unset($task); } mtrace("Cron script completed correctly"); gc_collect_cycles(); mtrace('Cron completed at ' . date('H:i:s') . '. Memory used ' . display_size(memory_get_usage()) . '.'); $difftime = microtime_diff($starttime, microtime()); mtrace("Execution took " . $difftime . " seconds"); }