safely re-raise exceptions with coroutine framework
If a exception raise in commit() function, rollback() function would be called and then the exception would be re-raised. The re-raising of the exception may be failed when sqlalchemy work with a coroutine framework such as evenlet or gevent due to a context switch(rollback is a bocking function, which will cause a context switch, and the exception may be cleared within the context switch). The issue could be simplely fixed by the following patch without risk.
Comments (9)
-
repo owner -
repo owner - marked as critical
-
Account Deleted I submited a new patch with a contextmanager class just now. I did a simple test(https://gist.github.com/layzerar/5386879) for it, it seems everything is okay.
-
repo owner OK thanks, I was working on a patch last night that includes some other things, including a new approach to py2k/3k exceptions. _handle_dbapi_exception() does an "autorollback" too, so the sys.exc_info() in there also needs to be stored, and I was thinking of having sys.exc_info() be passed into _handle_dbapi_exception() from the outside but i still need to play with it a bit.
-
repo owner check out the attached patch, make sure it works for you, I still need to ensure the Py3k "cause" handling works the way I'd like.
-
Account Deleted Hi zzzeek,
It's better to remove the reference of traceback object manually before reraise it(traceback object keep a large circular reference, there is some memory problem with a long-running program).
def __exit__(self, type_, value, traceback): if type_ is None: exc_type, exc_value, exc_tb = self._exc_info self._exc_info = None # remove the reference of traceback object manually compat.reraise(exc_type, exc_value, exc_tb) else: self._exc_info = None # remove the reference of traceback object manually compat.reraise(type_, value, traceback)
The following is the document of sys.exc_info from the python document:
Warning Assigning the traceback return value to a local variable in a function that is handling an exception will cause a circular reference. This will prevent anything referenced by a local variable in the same function or by the traceback from being garbage collected. Since most functions don’t need access to the traceback, the best solution is to use something like exctype, value = sys.exc_info():2 to extract only the exception type and value. If you do need the traceback, make sure to delete it after use (best done with a try ... finally statement) or to call exc_info() in a function that does not itself handle an exception.
cheers, layz
-
repo owner - changed status to resolved
0bb05ffdf066ba108883a0a4165cb11894fb3d88, and I added the setting _exc_info to None in 6d93918b9b68202fdcb1f76f865efd5cde154963
-
repo owner - removed milestone
Removing milestone: 0.8.xx (automated comment)
-
You don't have to backport the patch to 0.7.xx if you are using python-eventlet >= 0.13.
Related bug report: https://bugs.launchpad.net/ubuntu/+source/python-eventlet/+bug/1199037
Related commit: support: do not clear sys.exc_info if can be preserved (greenlet >= 0.3.2) https://bitbucket.org/eventlet/eventlet/commits/324e0eb952daa5fc53c686273e324b08ec67a45a
- Log in to comment
I'd like to see if this can be placed into a contextmanager function so that we aren't duplicating code like that in several places. using a common context manager also means we could theoretically vary how this case is handled based on up-front configuration.