-
Bug
-
Resolution: Unresolved
-
Minor
-
None
-
4.3.5
-
MOODLE_403_STABLE
The function enrol_cohort_sync() in /enrol/cohort/locallib.php is called by:
- A cohort being attached to a course through the UI or a bespoke plugin which creates cohort enrolments.
- The \enrol_cohort\task\enrol_cohort_sync cron task.
The function generates a list of users who need enrolling on a course due to being part of a cohort which is enrolled on that course, and then one-by-one, enrols them. However, it is possible that the second instance will generate its list before the first one has finished enrolling its list. This will cause both of them to try and enrol the same user on the same course using the same enrolment method. At which point, one of them will then fall over with a database error due to a duplicate index.
As these are potentially concurrent processes which are modifying the same data, they need some kind of locking mechanism. A database lock?
How to demonstrate... Extremely hard to do due to the precise timing required. But should be possible using the following steps:
- In /enrol/cohort/locallib.php, function enrol_cohort_sync(), find the first call to get_recordset_sql(). Immediately after it, add a sleep() call to sleep for 60 seconds.
- Check what time the scheduled task runs.
- Through the UI, attach a cohort to a course, hitting the button to start the process, within 60 seconds before or after the scheduled task starts.
You should see a failure - in the schedule task if you hit the button before it runs, or in the UI if you hit the button after it runs.