[ZODB-Dev] Automating retry management

Jim Fulton jim at zope.com
Tue May 11 11:49:15 EDT 2010


On Tue, May 11, 2010 at 11:35 AM, Laurence Rowe <l at lrowe.co.uk> wrote:
> On 11 May 2010 15:08, Jim Fulton <jim at zope.com> wrote:
>> On Tue, May 11, 2010 at 8:38 AM, Benji York <benji at zope.com> wrote:
>>> On Tue, May 11, 2010 at 7:34 AM, Jim Fulton <jim at zope.com> wrote:
>>>> [...] The best I've been
>>>> able to come up with is something like:
>>>>
>>>>    t = ZODB.transaction(3)
>>>>    while t.trying:
>>>>        with t:
>>>>            ... transaction body ...
>>>
>>> I think you could get this to work:
>>>
>>> for transaction in ZODB.retries(3):
>>>    with transaction:
>>>        ... transaction body ...
>>>
>>> ZODB.retries would return an iterator that would raise StopIteration on
>>> the next go-round if the previously yielded context manager exited
>>> without a ConflictError.
>>
>> This is an improvement. It's still unsatisfying, but I don't think I'm going to
>> get satisfaction. :)
>>
>> BTW, if I do something like this, I think I'll add a retry exception to
>> the transaction package and have ZODB.POSException.ConflictError
>> extend it so I can add the retry automation to the transaction package.
>
> The repoze.retry package lets you configure a list of exceptions.
> http://pypi.python.org/pypi/repoze.retry
> http://svn.repoze.org/repoze.retry/trunk/repoze/retry/__init__.py
>
>  Though it seems inspecting the error text is required for most sql
> database errors to know if they are retryable, as ZPsycoPGDA does:
>
>  188                 except (psycopg2.ProgrammingError,
> psycopg2.IntegrityError), e:
>  189                     if e.args[0].find("concurrent update") > -1:
>  190                         raise ConflictError
>
> (https://dndg.it/cgi-bin/gitweb.cgi?p=public/psycopg2.git;a=blob;f=ZPsycopgDA/db.py)
>
> For PostgreSQL it should be sufficient to catch these errors and raise
> Retry during tpc_vote.
>
> For databases which do not provide MVCC in the same way as PostgreSQL,
> concurrency errors could be manifested at any point in the
> transaction. Even Oracle can raise an error during a long running
> transaction when insufficient rollback space is available, resulting
> in what is essentially a read conflict error. Such errors could not be
> caught by a data manager and reraised as a Retry exception.
>
> I think it might be useful to add an optional method to data managers
> that is queried by the retry automation machinery to see if an
> exception should potentially be retried. Perhaps this would best be
> accomplished in two steps:
>
> 1. Add an optional property to data managers called ``retryable``.
> This is a list of potentially retryable exceptions. When a data
> manager is added to the transaction, the transaction's list of
> retryable exceptions is extended by the joining data managers list of
> retryable exceptions.
>
> t = transaction.begin()
> try:
>    application()
> except t.retryable, e:
>    t.retry(e):
>
> 2. t.retry(e) is then checks with each registered data manager if that
> particular exceptions is retryable, and if so raises Retry.
>
> def retry(self, e):
>    for datamanager in self._resources:
>        try:
>            retry = datamanager.retry
>        except AttributeError:
>            continue
>        if isinstance(e, datamanager.retryable):
>            datamanager.retry(e) # dm may raise Retry here

Thanks.

I don't think we need 1 and 2.
I'm inclined to go with 2.

Jim

-- 
Jim Fulton


More information about the ZODB-Dev mailing list