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 _______________________________________________ For more information about ZODB, see http://zodb.org/ ZODB-Dev mailing list - ZODB-Dev@zope.org https://mail.zope.org/mailman/listinfo/zodb-dev