Suppose I'm building a web application using Django. Some of the views need to touch multiple database tables or rows, and there is some kind of state consistency that I need to ensure among the records.
Here is a simple example, albeit a bit stupid. Suppose we're talking about an application for the management of class enrollment at a University.
- A student may enroll in a class only if that class is actually marked as open for enrollment.
- The school may freely toggle the class's open-to-enrollment status as long as there is no student currently enrolled.
- If there is any student already enrolled in a certain class, the school may not immediately close the class from enrollment and cancel it. The school would first need to send some kind of notification to the enrolled students and then wait for either 2 days or receiving all of the students' acknowledgement, whichever happens first.
So if in the database, a class is both closed from enrollment and has enrolled students, it is clearly in an inconsistent state. One way that can happen is if we forget to lock the class row in the views that handle open-to-enrollment status and student enrollment: the school may be trying to close the class from enrollment and a student may be trying to enroll at the same time. So, being a good engineer, I know I'm supposed to lock the class row. But even if I do that, how do I test and demonstrate that I have successfully prevented a race condition?
I mean, wouldn't that entail trying to cause a race condition on purpose? How would one even do that? Isn't that all about timing? If, in my tests, I naïvely fire two requests at the same time and I don't end up with an inconsistent state, how do I know it's because my row locking is correct and not because the two requests actually just missed each other?