From e0acbbc6ea14496df7ee5a7d721e64aac60e4c96 Mon Sep 17 00:00:00 2001 From: Andrew Nicols Date: Tue, 21 Mar 2023 13:22:28 +0800 Subject: [PATCH] MDL-77693 core: Check the start time of a cron run when fetching tasks When fetching the list of tasks to run, we were using the _process_ start time as a base. The various task fetchers (adhoc and scheduled) only fetch tasks which were due to run _before_ this time. With the new keepalive setting, we need to pass both the process start time, and the run start time. We need to use the process start time to determine whether MUC caches have been cleared since the process started. but the run start time to fetch recent runs. --- lib/classes/cron.php | 43 +++++++++++++++++++++++++++++++------------ lib/upgrade.txt | 1 + 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/lib/classes/cron.php b/lib/classes/cron.php index 79b7bbc7240..10f62c18a50 100644 --- a/lib/classes/cron.php +++ b/lib/classes/cron.php @@ -120,11 +120,12 @@ class cron { do { $startruntime = microtime(); + // Run all scheduled tasks. - self::run_scheduled_tasks($timenow); + self::run_scheduled_tasks(time(), $timenow); // Run adhoc tasks. - self::run_adhoc_tasks($timenow); + self::run_adhoc_tasks(time(), 0, true, $timenow); mtrace("Cron run completed correctly"); @@ -163,15 +164,23 @@ class cron { /** * Execute all queued scheduled tasks, applying necessary concurrency limits and time limits. * - * @param int $timenow The time this process started. + * @param int $startruntime The time this run started. + * @param null|int $startprocesstime The time the process that owns this runner started. * @throws \moodle_exception */ - public static function run_scheduled_tasks(int $timenow): void { + public static function run_scheduled_tasks( + int $startruntime, + ?int $startprocesstime = null, + ): void { // Allow a restriction on the number of scheduled task runners at once. $cronlockfactory = \core\lock\lock_config::get_lock_factory('cron'); $maxruns = get_config('core', 'task_scheduled_concurrency_limit'); $maxruntime = get_config('core', 'task_scheduled_max_runtime'); + if ($startprocesstime === null) { + $startprocesstime = $startruntime; + } + $scheduledlock = null; for ($run = 0; $run < $maxruns; $run++) { // If we can't get a lock instantly it means runner N is already running @@ -193,8 +202,8 @@ class cron { try { while ( !\core\local\cli\shutdown::should_gracefully_exit() && - !\core\task\manager::static_caches_cleared_since($timenow) && - $task = \core\task\manager::get_next_scheduled_task($timenow) + !\core\task\manager::static_caches_cleared_since($startprocesstime) && + $task = \core\task\manager::get_next_scheduled_task($startruntime) ) { self::run_inner_scheduled_task($task); unset($task); @@ -213,17 +222,27 @@ class cron { /** * Execute all queued adhoc tasks, applying necessary concurrency limits and time limits. * - * @param int $timenow The time this process started. + * @param int $startruntime The time this run started. * @param int $keepalive Keep this public static function alive for N seconds and poll for new adhoc tasks. * @param bool $checklimits Should we check limits? + * @param null|int $startprocesstime The time this process started. * @throws \moodle_exception */ - public static function run_adhoc_tasks(int $timenow, $keepalive = 0, $checklimits = true) { + public static function run_adhoc_tasks( + int $startruntime, + $keepalive = 0, + $checklimits = true, + ?int $startprocesstime = null, + ): void { // Allow a restriction on the number of adhoc task runners at once. $cronlockfactory = \core\lock\lock_config::get_lock_factory('cron'); $maxruns = get_config('core', 'task_adhoc_concurrency_limit'); $maxruntime = get_config('core', 'task_adhoc_max_runtime'); + if ($startprocesstime === null) { + $startprocesstime = $startruntime; + } + $adhoclock = null; if ($checklimits) { for ($run = 0; $run < $maxruns; $run++) { @@ -241,18 +260,18 @@ class cron { } } - $humantimenow = date('r', $timenow); - $finishtime = $timenow + $keepalive; + $humantimenow = date('r', $startruntime); + $finishtime = $startruntime + $keepalive; $waiting = false; $taskcount = 0; // Run all adhoc tasks. while ( !\core\local\cli\shutdown::should_gracefully_exit() && - !\core\task\manager::static_caches_cleared_since($timenow) + !\core\task\manager::static_caches_cleared_since($startprocesstime) ) { - if ($checklimits && (time() - $timenow) >= $maxruntime) { + if ($checklimits && (time() - $startruntime) >= $maxruntime) { if ($waiting) { $waiting = false; mtrace(''); diff --git a/lib/upgrade.txt b/lib/upgrade.txt index d2e4114280f..0bf366ab15f 100644 --- a/lib/upgrade.txt +++ b/lib/upgrade.txt @@ -94,6 +94,7 @@ information provided here is intended especially for developers. - groups_get_groups_members() groups_print_activity_menu() will now only return groups where particiation == true. * Cron utility functions have been moved from the global namespaces to the \core\cron class. +* The `run_scheduled_tasks` and `run_adhoc_tasks` functions take an additional parameter to calculate the start of a run. * The following phpunit advanced testcase helper methods, deprecated since 3.10, have been removed and can no longer be used: - `createXMLDataSet` - `createCsvDataSet`