beaker
beaker copied to clipboard
Beaker sessions lose information with concurrent AJAX requests from the same browser
I'm facing an issue that is a result of race conditions. Beaker sessions seem to mysteriously lose information or retain deleted information.
I'm running a (multithreaded) system which runs timed status checks. Each of these checks is an Ajax request. Each of these requests checks against session for the active user.
A certain operation - opening file contents - requires that I associate a (unique) ID with a filepath (and an html link) so that I can open the right file when its link is clicked. The association is done through another Ajax request. The problem arises when the association is done during the timespan of a previous request. When the previous request returns, it overwrites the session info with the previous content of session.
To illustrate better:
getjobs - before - session: {} jobinfo - before - session: {} jobinfo - after - session: {'b7b57eb3-e05c-4854-87a1-96e74d9f4e38': u'/foo/bar.log'} getjobs - after - session: {} getjobs - before - session: {} getjobs - after - session: {} getjobs - before - session: {}
Sessions are not 'auto', and are saved to database. JobInfo request (above) is the only one calling session.save()
Confirm. Got same issue. Beaker == 1.6.4, Pylons == 1.0.1
This is a known issue with concurrent requests, and is due to the fact that at the beginning of a request the session is read, its updated, then written back. Even though the read/write's are done with locks, that doesn't help since one both requests read the same session at approximately the same exact time.
The only way to fix this (depending on session back-end), is very ugly, which is to lock requests making it impossible for one request to start if another one is using the same session. This way one of the sessions has to wait before it can even read, thus ensuring it doesn't overwrite newer data. Alternatively, a more proactive version could be done where during write, if beaker sees that your sessions 'origin' time is no longer the same, it could deny the save and force you to reload it.
Locking during the entire request is a no-go, but reading an 'origin' time for the session and checking it before saving it is do-able, this way the code could reload the session or take whatever step it wants. Perhaps it could be re-read and the keys merged.
I'm open to pull requests implementing the optimistic save feature to prevent overwrites, but its likely not trivial and will involve:
- Update the back-end API to ensure an 'origin' time is read.
- Update the back-end API to ensure the save command also takes the origin time for checking with the back-end
- Update all the core backends in Beaker to support the two new options
- Update the Session code to support the new features in the container code
- Add tests to ensure the optimistic overwriting prevention is handled correctly
So, who's up for it? :)