[ZODB-Dev] transaction "Attempts" class

Thierry Florac tflorac at ulthar.net
Wed Mar 28 06:33:17 UTC 2012


Le Wed, 28 Mar 2012 02:08:24 -0400, Chris McDonough <chrism at plope.com>
a �crit:

> 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?

I used this feature just a few days ago.
It was in a batch application where conflict errors can frequently
occur, and they **seemed** to be handled correctly.

My only problem is that I had to add a "break" at the end of my "for"
loop. Otherwise the transaction was committed several times and the mail
report which was sent at the end of the batch was also sent several
times... Did I missed something ? Otherwise perhaps the 'transaction'
package documentation should be updated ??

Best regards,
Thierry



More information about the ZODB-Dev mailing list