Right now, when a customer goes to the registration page, they see a count of current registrants and the option to register themselves based on the number of completed registrations in the system. Once they select 1 or more class series and click the register now button, their choice is entered into temporary session data and they proceed to step 2, where they fill out their name and email, etc. That info is also loaded into temporary session data and they proceed to step 3. In Step 3, the session data is read and used to create a "Temporary Registration" object, applying any discounts or vouchers that they have entered in the process. They are displayed a page with a final summary and typically a payment link. When they click the payment link, the callback to our website creates an "Invoice" object indicating intent to finish registration, and when they finish paying with Paypal, the Invoice is marked as paid, which triggers the Temporary Registration object to be used to create a Final Registration object, and the user is redirected to the success page. Registration session data expires after 15 minutes of inactivity, so if a customer takes too long they are just redirected to start over.
So, right now, , it is still theoretically possible to have a class over-registered by one or two people if multiple people try to register for the last spot simultaneously. For most small series classes this is not a big issue in the experience of BLH. But, the registration system should be general enough to cover registration for larger events where this might be an issue, especially for something like registration-count based pricing tiers where it's important to keep a running count that includes people who have started but not completed the registration process. Per issue #2 , I'd also like to implement private lesson scheduling, in which each item that can be registered for can only be selected by one person, in which case real-time monitoring of in-progress registrations is potentially important.
Upon some reflection, I think that the best solution for this is going to be to create a separate table with three fields:
- a key for matching the row up to a particular customer's registration session data
- The id of the class series or private lesson slot for which they are in the process of registering
- an expiration time
In Step 1, when a customer goes to sign up for a class series, the site looks for how many people have registered plus how many unexpired rows are in the cache table from people who are still in the process of registering for that class, and permits or disallows registration from beginning based on that. As the customer proceeds through the steps of the registration process, the site should also updates the expiration time. For private lessons, since there's only one slot available, that also effectively prevents duplicate booking entirely.
Since many users of this project won't care much about this functionality, I'm inclined to keep it simple while providing the option for enhanced performance. But, we also need to be able to query this as a table, not just as a set of individual cache keys (which from my research, seems like it rules out most standard cache store options). So, for now, this should probably be a standard database table that is queried using the regular ORM and a management command to clean out stale entries, similar to the way that Django's default database-backed session store works. If someone needs this to be higher-performance than is feasible with a disk-based database, they should be able to configure their installation to improve performance considerably by routing this particular table to be handled by something like an in-memory SQLite or MySQL database.
My knowledge on these issues is limited, so I welcome comments from anyone who has experience with these kinds of performance questions. @afs2015 @Kirkalicious @NorthIsUp .