phpmoodlecron-task

Moodle "Background processing for assignment module" failing due to a missing record


Moodle 4.1.4, MSSQL, PHP 8.1

The scheduled task, \mod_assign\task\cron_task, keeps failing because it is trying to read an assignment that isn't there (I think).  The full error message is:

Execute scheduled task: Background processing for assignment module (mod_assign\task\cron_task)
... started 09:11:36. Current memory use 20.7 MB.
Debugging increased temporarily due to faildelay of 120
... used 468 dbqueries
... used 1.6565690040588 seconds
Scheduled task failed: Background processing for assignment module (mod_assign\task\cron_task),Can't find data record in database.
Debug info:
SELECT cm.*, m.name, md.name AS modname 
              FROM {course_modules} cm
                   JOIN {modules} md ON md.id = cm.module
                   JOIN {assign} m ON m.id = cm.instance
                   
             WHERE m.id = :instance AND md.name = :modulename
                   
[array (
  'instance' => '341',
  'modulename' => 'assign',
)]
Backtrace:
* line 1317 of \lib\datalib.php: call to moodle_database->get_record_sql()
* line 2849 of \mod\assign\locallib.php: call to get_coursemodule_from_instance()
* line 44 of \mod\assign\classes\task\cron_task.php: call to assign::cron()
* line 263 of \lib\cronlib.php: call to mod_assign\task\cron_task->execute()
* line 120 of \lib\cronlib.php: call to cron_run_inner_scheduled_task()
* line 73 of \lib\cronlib.php: call to cron_run_scheduled_tasks()
* line 178 of \admin\cli\cron.php: call to cron_run()

I don't know how I can stop it from trying to access this assignment. Has anyone else experienced this?

I have cleared the errors but they just keep occurring.


Solution

  • That's a tricky one to fix, it looks like the course module has been deleted but the assignment still exists.

    If you take a look at the code at the end of public static function cron() in /mod/assign/locallib.php

    // Update calendar events to provide a description.
    $sql = 'SELECT id
                FROM {assign}
                WHERE
                    allowsubmissionsfromdate >= :lastruntime AND
                    allowsubmissionsfromdate <= :timenow AND
                    alwaysshowdescription = 0';
    $params = array('lastruntime' => $lastruntime, 'timenow' => $timenow);
    $newlyavailable = $DB->get_records_sql($sql, $params);
    foreach ($newlyavailable as $record) {
        $cm = get_coursemodule_from_instance('assign', $record->id, 0, false, MUST_EXIST);
        $context = context_module::instance($cm->id);
    
        $assignment = new assign($context, null, null);
        $assignment->update_calendar($cm->id);
    }
    

    It's looping through assignments and updating the calendar but the course module doesn't exist

    You could try checking the log to see when the assignment was deleted and by who

    SELECT logs.contextid AS coursemoduleid, logs.userid, u.firstname, u.lastname, logs.action, logs.*
    FROM mdl_logstore_standard_log logs
    JOIN (
        SELECT DISTINCT loghistory.contextid
        FROM mdl_logstore_standard_log loghistory
        WHERE loghistory.objecttable = 'assign'
        AND loghistory.objectid = 341 /* assign id */
    ) deletedassign ON logs.contextid = deletedassign.contextid AND logs.contextlevel = 70 /* course modules only */
    LEFT JOIN mdl_user u ON u.id = logs.userid
    ORDER BY logs.timecreated DESC
    LIMIT 10
    

    The latest action should be deleted - if it isn't, then the course module record has probably been deleted by some faulty code or custom code or manually in SQL

    A quick fix would be to update alwaysshowdescription to 1 so its not included in the loop, but that might create problems elsewhere

    UPDATE mdl_assign
    SET alwaysshowdescription = 1
    WHERE id = 341
    

    Also maybe check to see if there are any other assignments with a missing course module, if there's more than 1 then it could be a bigger issue

    SELECT *
    FROM mdl_assign a
    LEFT JOIN mdl_course c ON c.id = a.course
    WHERE NOT EXISTS (
        SELECT cm.id
        FROM mdl_course_modules cm
        JOIN mdl_modules m ON m.id = cm.module AND m.name = 'assign'
        WHERE cm.instance = a.id
    )