[ZODB-Dev] transaction "Attempts" class

Chris McDonough chrism at plope.com
Wed Mar 28 06:08:24 UTC 2012


The transaction package offers a nice feature, where you can say:

    import transaction

    for attempt in transaction.attempts(3):
        with attempt as t:
            ... do something ...

If "do something" raises a ConflictError (or any other retryable error),
the next attempt is tried, until all attempts have been exhausted, at
which point, it gives up and the exception is raised.

But I think it may be slightly broken.

Here's the definition of the "attempt" context manager:

class Attempt(object):

    def __init__(self, manager):
        self.manager = manager

    def __enter__(self):
        return self.manager.__enter__()

    def __exit__(self, t, v, tb):
        if v is None:
            self.manager.commit()
        else:
            retry = self.manager._retryable(t, v)
            self.manager.abort()
            return retry

"do_something" within the body of an "attempt" context manager usually
doesn't raise a retryable exception (it's business logic), but the
"self.manager.commit()" within the __exit__ of the context manager
usually does.  When this happens, nothing actually catches the
exception.  I think the context manager may need to be changed to this:

class Attempt(object):

    def __init__(self, manager):
        self.manager = manager

    def __enter__(self):
        return self.manager.__enter__()

    def __exit__(self, t, v, tb):
        if v is None:
            try:
                self.manager.commit()
            except:
                retry = self.manager._retryable(*sys.exc_info()[:2])
                self.manager.abort()
                return retry
        else:
            retry = self.manager._retryable(t, v)
            self.manager.abort()
            return retry

Either that or it needs to not try to do a commit itself, and leave it
up to the caller.

Anybody with thoughts?

- C




More information about the ZODB-Dev mailing list