[Zope-dev] kudos...

Chris McDonough chrism at plope.com
Tue Aug 9 13:19:59 EDT 2011


On Tue, 2011-08-09 at 11:48 -0400, Zvezdan Petkovic wrote:
> On Aug 8, 2011, at 4:44 PM, Chris McDonough wrote:
> 
> > Kudos to whomever turned the "transaction" package's transaction manager into a context manager and was thoughtful enough to provide the "attempts" method (which returns a separate context manager, wrapping the txn context manager, and retries some number of configurable times).
> > This makes writing code that integrates with a web system that commits
> > or aborts as easy as:
> > 
> >         import transaction
> > 
> >         for attempt in transaction.attempts(attempts):
> >            with attempt as t:
> >                response = handler(request)
> > 
> >                if t.isDoomed():
> >                    t.abort()
> > 
> >                if commit_veto is not None:
> >                    veto = commit_veto(request, response)
> >                    veto and t.abort()
> > 
> >                return response
> > 
> > Very nice.
> > 
> > - C
> 
> 
> Yes, this is *very* convenient and I like to use it, but beware of the bug (it's not affecting you above because of the return).
> 
> According to the documentation, it's intended as a replacement for:
> 
>     for i in range(3):
>         try:
>            with transaction:
>                ... some something ...
>         except SomeTransientException:
>            continue
>         else:
>            break
> 
> So, presumably,
> 
>     for attempt in transanction.attempts(retries):
>         with attempt as tx:
>             do_something()
> 
> should break after the *first* successful commit.
> 
> It doesn't.  Instead, it commits do_something() ``retries`` times which is most probably not intended.

Not sure about that; I just return a value if it succeeds.  I wouldnt
expect it to know to break out of the loop without a return in there.

I wound up with this, FWIW:

def tm_tween_factory(handler, registry, transaction=transaction):
    # transaction parameterized for testing purposes
    commit_veto = registry.settings.get('pyramid_tm.commit_veto',
                                        default_commit_veto)
    attempts = int(registry.settings.get('pyramid_tm.attempts', 1))

    if not commit_veto:
        commit_veto = None
    else:
        commit_veto = resolver.maybe_resolve(commit_veto)

    def tm_tween(request):
        if 'repoze.tm.active' in request.environ:
            # don't handle txn mgmt if repoze.tm is in the WSGI pipeline
            return handler(request)

        try:
            for attempt in transaction.attempts(attempts):
                with attempt as t:
                    # make_body_seekable will copy wsgi.input if
                    # necessary, otherwise it will rewind the copy
                    # to position zero
                    if attempts != 1:
                        request.make_body_seekable()
                    response = handler(request)
                    if t.isDoomed():
                        raise AbortResponse(response)
                    if commit_veto is not None:
                        veto = commit_veto(request, response)
                        if veto:
                            raise AbortResponse(response)
                    return response
        except AbortResponse, e:
            return e.response

    return tm_tween

A little more verbose but still nice.

> 
> See https://bugs.launchpad.net/transaction/+bug/724332
> The patch attached to the bug report is just a test that proves that behavior is unexpected and gives a workaround.
> 
> The workaround is simple enough and I prefer to use transaction.attempts convenience rather than the typical try-except code above.
> 
> Still, we really should find time to fix this in the transaction manager code so that it behaves as expected. (Or change the documentation and tests).
> 
> Regards,
> 
>     Zvezdan
> 
> _______________________________________________
> Zope-Dev maillist  -  Zope-Dev at zope.org
> https://mail.zope.org/mailman/listinfo/zope-dev
> **  No cross posts or HTML encoding!  **
> (Related lists - 
>  https://mail.zope.org/mailman/listinfo/zope-announce
>  https://mail.zope.org/mailman/listinfo/zope )
> 




More information about the Zope-Dev mailing list