safely re-raise exceptions with coroutine framework

Issue #2703 resolved
Former user created an issue

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)

  1. Mike Bayer repo owner

    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.

  2. Mike Bayer 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.

  3. Mike Bayer 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.

  4. Former user 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

  5. Log in to comment