-
Notifications
You must be signed in to change notification settings - Fork 25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Raise AttributeError on request.tm
if tm inactive
#46
Conversation
This will allow the `request.tm` request property to determine whether or not the transaction manager is active for the current request and thus whether to return a reference to the manager to the caller.
I reckon it's probably time to do a bit of cleanup of the core loop in the tween, but I didn't want to confuse the issue by doing any refactoring in this PR. Happy to follow up with a bit of cleanup. Perhaps we can use |
60889aa
to
ce1179a
Compare
Opening a database session to load feature flags for these requests is not only not necessary, it is quite problematic. It causes the leakage of references to the database session inside `zope.sqlalchemy` because these requests have been opted out of the transaction manager by an `activate_hook` (see `h.app`). By using the database in these requests, we were accidentally registering a database session with a transaction manager that wasn't hooked up to the request lifecycle. This meant that zope.sqlalchemy's internal references to the session weren't properly cleaned up. In a high traffic environment -- these leaked session references would then later lead to a session (in an entirely different request) not being correctly registered with the transaction manager. I've also opened a pull request against `pyramid_tm` which should prevent this class of bug in the future: Pylons/pyramid_tm#46
Opening a database session to load feature flags for these requests is not only not necessary, it is quite problematic. It causes the leakage of references to the database session inside `zope.sqlalchemy` because these requests have been opted out of the transaction manager by an `activate_hook` (see `h.app`). By using the database in these requests, we were accidentally registering a database session with a transaction manager that wasn't hooked up to the request lifecycle. This meant that zope.sqlalchemy's internal references to the session weren't properly cleaned up. In a high traffic environment -- these leaked session references would then later lead to a session (in an entirely different request) not being correctly registered with the transaction manager. I've also opened a pull request against `pyramid_tm` which should prevent this class of bug in the future: Pylons/pyramid_tm#46
@@ -50,6 +50,9 @@ def tm_tween(request): | |||
if not activate(request): | |||
return handler(request) | |||
|
|||
# Set a flag in the environment to enable the `request.tm` property. | |||
request.environ['tm.active'] = True |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there should be a guard against something else setting tm.active
similar to the guard against repoze.tm.active
as transaction cannot be nested
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep. Added.
I cannot remember the reason off the top of my head but pyramid_tm used to use This PR looks good, just address the one comment and add your name to CONTRIBUTORS.txt in the repo. |
This makes it much harder for an application to mistakenly get hold of a reference to the transaction manager during a request for which the activate_hook returns `False`. There should never be any need to get a reference to the transaction manager during a request that has been opted out. The ability to do so opens up possibilities for subtle bugs where database sessions are registered with a manager that isn't itself hooked up to the request lifecycle, resulting in leaked references to those sessions inside `zope.sqlalchemy`.
ce1179a
to
91b6465
Compare
And it looks like we stopped using So it may be that switching back to that will work fine as long as we're ok to require |
Sure, you're welcome to consider that in a separate PR but I'm not likely to accept it quite yet... you'll see in #42 where going back to |
This PR addresses the issue raised in #45.
Raising an
AttributeError
forrequest.tm
if the current request doesn't have an active transaction manager makes it much harder for an application to mistakenly get hold of a reference to a transaction manager which is not committed (or rolled back) at the end of the request.There should never be any need to get a reference to the transaction manager during a request that has been opted out using an
activate_hook
. The ability to do so opens up possibilities for subtle bugs where database sessions are registered with a manager that isn't itself hooked up to the request lifecycle, resulting in leaked references to those sessions insidezope.sqlalchemy
.As suggested in #45, this is implemented by adding
tm.active
to the WSGI environment on the way through the tween, and removing it on the way out.