feat!: rm user db_constraint in CourseEnrollment#38810
Conversation
(cherry picked from commit a022b69)
|
Thanks for the pull request, @johanseto! This repository is currently maintained by Once you've gone through the following steps feel free to tag them in a comment and let them know that your changes are ready for engineering review. 🔘 Get product approvalIf you haven't already, check this list to see if your contribution needs to go through the product review process.
🔘 Provide contextTo help your reviewers and other members of the community understand the purpose and larger context of your changes, feel free to add as much of the following information to the PR description as you can:
🔘 Submit a signed contributor agreement (CLA)
If you've signed an agreement in the past, you may need to re-sign. Once you've signed the CLA, please allow 1 business day for it to be processed. 🔘 Get a green buildIf one or more checks are failing, continue working on your changes until this is no longer the case and your build turns green. DetailsWhere can I find more information?If you'd like to get more details on all aspects of the review process for open source pull requests (OSPRs), check out the following resources: When can I expect my changes to be merged?Our goal is to get community contributions seen and reviewed as efficiently as possible. However, the amount of time that it takes to review and merge a PR can vary significantly based on factors such as:
💡 As a result it may take up to several weeks or months to complete a review and merge your PR. |
|
Hi @johanseto! Welcome, and thank you for this contribution! In order for your CLA check to turn green, you'll need to submit a CLA form. If you are contributing as an individual, please fill out the individual CLA form here. If you are contributing on behalf of an organization, please have your manager reach out to oscm@axim.org so you may be added to your org's existing entity agreement. Please let me know if you have any questions. Thanks! |
Title: Refactor: Remove Database Foreign Key Constraint on User Table in CourseEnrollment
Inspired by the courseware student module's good performance.
openedx-platform/lms/djangoapps/courseware/models.py
Line 95 in b1b59dd
1. Context & Architecture
The
CourseEnrollmentmodel is a critical piece of the application's core logic, tracking the many-to-many relationship between users and the courses they are enrolled in. Historically, the database schema linked theCourseEnrollmentto the centralUsertable using a strict database-level Foreign Key (FK) constraint to enforce referential integrity.2. The Problem: High-Traffic Lock Contention on the User Table
In scenarios involving mass enrollments or high concurrency (e.g., thousands of students joining a course simultaneously at the start of a semester), the strict database-level Foreign Key constraint introduces a major performance bottleneck.
Whenever an application inserts or updates a
CourseEnrollmentrow, the relational database engine (e.g., MySQL or PostgreSQL) acquires a shared read lock on the corresponding row in the parentUsertable to guarantee that the referenced user exists. Because theUsertable is centrally accessed and locked by numerous other services and domains simultaneously, this causes contention.The resulting lock queues drastically slow down all database transactions touching the
Usertable, causing latency spikes, connection pool exhaustion, and potentially triggering application-wide timeouts and deadlocks during periods of heavy traffic.3. The Solution
This PR removes the database-level enforcement of the foreign key constraint on the
Usertable within theCourseEnrollmentmodel (e.g., by utilizingdb_constraint=Falsein the Django model field).To ensure data integrity is maintained at the application level, a safety check has been established within the model layer:
get_or_create_enrollmentis strictly interacting with a validUserobject (rather than raw integer IDs).Userobject is passed (i.e., one lacking an.id), the application explicitly forces auser.save()before attempting to log the enrollment. This guarantees we have a real identifier mapped in theCourseEnrollmenttable, thus avoiding a potentialIntegrityErrordue to a nulluser_id.4. Impact & Benefits
CourseEnrollmentfrom locks on theUsertable allows enrollment inserts/updates to execute concurrently and independently without queuing behind lock states.Usertable.5. Trade-offs & Considerations
CourseEnrollmentrecords either inline or via asynchronous background jobs.Consideration
The model get_or_create receives an user object. So is controlled that user is used to create a course_enrollment without using a random int.
openedx-platform/common/djangoapps/student/models/course_enrollment.py
Lines 375 to 407 in a022b69
Test
Run migrations
Inspired also by PR nelc#78
similar approach in openedx/completion#443