diff --git a/lib/classes/task/manager.php b/lib/classes/task/manager.php index d4e09f9ac47..d1121728505 100644 --- a/lib/classes/task/manager.php +++ b/lib/classes/task/manager.php @@ -66,8 +66,11 @@ class manager { foreach ($tasks as $task) { $record = (object) $task; $scheduledtask = self::scheduled_task_from_record($record); - $scheduledtask->set_component($componentname); - $scheduledtasks[] = $scheduledtask; + // Safety check in case the task in the DB does not match a real class (maybe something was uninstalled). + if ($scheduledtask) { + $scheduledtask->set_component($componentname); + $scheduledtasks[] = $scheduledtask; + } } return $scheduledtasks; @@ -237,6 +240,7 @@ class manager { $classname = '\\' . $classname; } if (!class_exists($classname)) { + debugging("Failed to load task: " . $classname, DEBUG_DEVELOPER); return false; } $task = new $classname; @@ -272,6 +276,7 @@ class manager { $classname = '\\' . $classname; } if (!class_exists($classname)) { + debugging("Failed to load task: " . $classname, DEBUG_DEVELOPER); return false; } /** @var \core\task\scheduled_task $task */ @@ -328,7 +333,10 @@ class manager { $records = $DB->get_records('task_scheduled', array('componentname' => $componentname), 'classname', '*', IGNORE_MISSING); foreach ($records as $record) { $task = self::scheduled_task_from_record($record); - $tasks[] = $task; + // Safety check in case the task in the DB does not match a real class (maybe something was uninstalled). + if ($task) { + $tasks[] = $task; + } } return $tasks; @@ -362,8 +370,12 @@ class manager { */ public static function get_default_scheduled_task($classname) { $task = self::get_scheduled_task($classname); + $componenttasks = array(); - $componenttasks = self::load_default_scheduled_tasks_for_component($task->get_component()); + // Safety check in case no task was found for the given classname. + if ($task) { + $componenttasks = self::load_default_scheduled_tasks_for_component($task->get_component()); + } foreach ($componenttasks as $componenttask) { if (get_class($componenttask) == get_class($task)) { @@ -387,7 +399,10 @@ class manager { foreach ($records as $record) { $task = self::scheduled_task_from_record($record); - $tasks[] = $task; + // Safety check in case the task in the DB does not match a real class (maybe something was uninstalled). + if ($task) { + $tasks[] = $task; + } } return $tasks; @@ -418,6 +433,11 @@ class manager { if ($lock = $cronlockfactory->get_lock('adhoc_' . $record->id, 10)) { $classname = '\\' . $record->classname; $task = self::adhoc_task_from_record($record); + // Safety check in case the task in the DB does not match a real class (maybe something was uninstalled). + if (!$task) { + $lock->release(); + continue; + } $task->set_lock($lock); if (!$task->is_blocking()) { @@ -463,6 +483,11 @@ class manager { if ($lock = $cronlockfactory->get_lock(($record->classname), 10)) { $classname = '\\' . $record->classname; $task = self::scheduled_task_from_record($record); + // Safety check in case the task in the DB does not match a real class (maybe something was uninstalled). + if (!$task) { + $lock->release(); + continue; + } $task->set_lock($lock); diff --git a/lib/tests/scheduled_task_test.php b/lib/tests/scheduled_task_test.php index c29e7f8d878..bb81535d0a4 100644 --- a/lib/tests/scheduled_task_test.php +++ b/lib/tests/scheduled_task_test.php @@ -214,4 +214,32 @@ class core_scheduled_task_testcase extends advanced_testcase { $task = \core\task\manager::get_next_scheduled_task($now); $this->assertNull($task); } + + public function test_get_broken_scheduled_task() { + global $DB; + + $this->resetAfterTest(true); + // Delete all existing scheduled tasks. + $DB->delete_records('task_scheduled'); + // Add a scheduled task. + + // A broken task that runs all the time. + $record = new stdClass(); + $record->blocking = true; + $record->minute = '*'; + $record->hour = '*'; + $record->dayofweek = '*'; + $record->day = '*'; + $record->month = '*'; + $record->component = 'test_scheduled_task'; + $record->classname = '\core\task\scheduled_test_task_broken'; + + $DB->insert_record('task_scheduled', $record); + + $now = time(); + // Should not get any task. + $task = \core\task\manager::get_next_scheduled_task($now); + $this->assertDebuggingCalled(); + $this->assertNull($task); + } }