Uploaded image for project: 'Moodle'
  1. Moodle
  2. MDL-84456

Asynchronous course copy is marked as successful when backup controller cannot be loaded

XMLWordPrintable

    • MOODLE_401_STABLE, MOODLE_404_STABLE, MOODLE_405_STABLE
    • MDL-84456-main
    • Hide

      Testing Instructions

      1. Apply changes from MDL-84456-main branch
      2. Visit admin/settings.php?section=asyncgeneralsettings, enable 'coursebinenable'
      3. Create new 'XS' test course
      4. Visit Course > More > Course Reuse > Copy course
      5. Enter required fields, then click 'Copy and return'
      6. To simulate failed backup controller loading, change Line 62 in lib/classes/task/asynchronous_copy_task.php to:

        $bc = \backup_controller::load_controller("aaa"); // Get the backup controller by backup id.
        

      7. Run the task by running command:

        php admin/cli/adhoc_task.php --execute 

      8. Check that task output includes the stacktrace:

        Execute adhoc task: core\task\asynchronous_copy_task
        Adhoc task id: 10
        Adhoc task custom data: {"backupid":"9d6f809aaaa9652f80273923351e0724","restoreid":"7622791fc8dacba6e701125045811d84"}
        ... started 00:19:05. Current memory use 40.1 MB.
        Course copy: Processing asynchronous course copy for course id: 2
        Course copy: Can not load backup controller for copy, marking job as failed
        ... used 452 dbqueries
        ... used 0.3505551815033 seconds
        Adhoc task failed: core\task\asynchronous_copy_task,error/backup_controller_dbops_nonexisting
        Backtrace:
        * line 604 of /backup/controller/backup_controller.class.php: call to backup_controller_dbops::load_controller()
        * line 62 of /lib/classes/task/asynchronous_copy_task.php: call to backup_controller::load_controller()
        * line 519 of /lib/classes/cron.php: call to core\task\asynchronous_copy_task->execute()
        * line 302 of /lib/classes/cron.php: call to core\cron::run_inner_adhoc_task()
        * line 174 of /admin/cli/adhoc_task.php: call to core\cron::run_adhoc_tasks()

      9. Check that latest task run is marked as failed in admin/tasklogs.php
      Show
      Testing Instructions Apply changes from MDL-84456 -main branch Visit admin/settings.php?section=asyncgeneralsettings, enable 'coursebinenable' Create new 'XS' test course Visit  Course > More > Course Reuse > Copy course Enter required fields, then c lick 'Copy and return' To simulate failed backup controller loading, change Line 62 in lib/classes/task/asynchronous_copy_task.php to: $bc = \backup_controller::load_controller( "aaa" ); // Get the backup controller by backup id. Run the task by running command: php admin/cli/adhoc_task.php --execute Check that task output includes the stacktrace: Execute adhoc task: core\task\asynchronous_copy_task Adhoc task id: 10 Adhoc task custom data: { "backupid" : "9d6f809aaaa9652f80273923351e0724" , "restoreid" : "7622791fc8dacba6e701125045811d84" } ... started 00 : 19 : 05 . Current memory use 40.1 MB. Course copy: Processing asynchronous course copy for course id: 2 Course copy: Can not load backup controller for copy, marking job as failed ... used 452 dbqueries ... used 0.3505551815033 seconds Adhoc task failed: core\task\asynchronous_copy_task,error/backup_controller_dbops_nonexisting Backtrace: * line 604 of /backup/controller/backup_controller. class .php: call to backup_controller_dbops::load_controller() * line 62 of /lib/classes/task/asynchronous_copy_task.php: call to backup_controller::load_controller() * line 519 of /lib/classes/cron.php: call to core\task\asynchronous_copy_task->execute() * line 302 of /lib/classes/cron.php: call to core\cron::run_inner_adhoc_task() * line 174 of /admin/cli/adhoc_task.php: call to core\cron::run_adhoc_tasks() Check that latest task run is marked as failed in admin/tasklogs.php
    • Hide

      Code verified against automated checks.

      Checked MDL-84456 using repository: https://github.com/djarran/moodle

      More information about this report

      Built on: Fri Feb 7 12:36:29 AM UTC 2025

      Show
      Code verified against automated checks. Checked MDL-84456 using repository: https://github.com/djarran/moodle main (0 errors / 0 warnings) [branch: MDL-84456-main | CI Job ] More information about this report Built on: Fri Feb 7 12:36:29 AM UTC 2025

      When copying a course, the task may fail with the following error with no stacktrace:

      > Course copy: Can not load backup controller for copy, marking job as failed

      This is because we catch the error and only print the above message:

      https://github.com/moodle/moodle/blob/139a0ad5f0458caaff7506c8b26081eea1c85231/lib/classes/task/asynchronous_copy_task.php#L60

              mtrace('Course copy: Processing asynchronous course copy for course id: ' . $backuprecord->itemid);
              try {
                  $bc = \backup_controller::load_controller($backupid); // Get the backup controller by backup id.
              } catch (\backup_dbops_exception $e) {
                  mtrace('Course copy: Can not load backup controller for copy, marking job as failed');
                  delete_course($restorerecord->itemid, false); // Clean up partially created destination course.
                  return; // Return early as we can't continue.
              }
       

      It would make debugging task failures easier if the stacktrace was displayed.

      Looking at the 'asynchronous_backup_task', `load_controller` is called without a try/catch block. For this task, we catch the error because we need to cleanup the destination course, but we don't rethrow the error. This means we cannot tell which of the three errors are thrown:

          public static function load_controller($backupid) {
              global $DB;
              if (! $controllerrec = $DB->get_record('backup_controllers', array('backupid' => $backupid))) {
                  throw new backup_dbops_exception('backup_controller_dbops_nonexisting');
              }
              $controller = unserialize(base64_decode($controllerrec->controller));
              if (!is_object($controller)) {
                  // The controller field of the table did not contain a serialized object.
                  // It is made empty after it has been used successfully, it is likely that
                  // the user has pressed the browser back button at some point.
                  throw new backup_dbops_exception('backup_controller_dbops_loading_invalid_controller');
              }
              // Check checksum is ok. Sounds silly but it isn't ;-)
              if (!$controller->is_checksum_correct($controllerrec->checksum)) {
                  throw new backup_dbops_exception('backup_controller_dbops_loading_checksum_mismatch');
              }
              return $controller;
          } 

            djarran Djarran Cotleanu
            djarran Djarran Cotleanu
            Votes:
            1 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated:

                Error rendering 'clockify-timesheets-time-tracking-reports:timer-sidebar'. Please contact your Jira administrators.