[ZODB-Dev] ZODB 3.2.4 ConnectionStateError

Tim Peters tim at zope.com
Fri Nov 12 12:06:41 EST 2004


[Tim Peters]
>>> You're never *not* "in" a transaction.  The instant abort() returns, a
>>> new transaction has implicitly begun.  So, yes, it's safe to access
>>> objects after aborting, but you're technically in a new transaction
>>> then.  If you modify any of these objects, you'll again need to abort
>>> or commit the transaction before closing the connection.

[Syver Enstad]
> The problem here arises when one does something like this:
>
> connection = db.open()
> try:
>     for each in connection.root()['mycollection']:
>         each.setSomeState(arg)
>     connection.getTransaction().commit()
> finally:
>     connection.close()
>
> If each.setSomeState raises for some reason after having modified this
> code will fail to close the connection which is pretty bad.

Of course it won't just fail to close the connection, the *attempt* to close
the connection will raise a new exception.  Whether that's "bad" or not
depends on code you haven't shown (the code that would deal, or fail to
deal, with the new ConnectionStateError).

> Is this the correct version of the code above:

Can't say -- "correct" depends on details of your app, and your overall
goals.

> connection = db.open()
> try:
>     try:
>         for each in connection.root()['mycollection']:
>             each.setSomeState(arg)
>     except:
>         connection.getTransaction().abort()
>         raise
>     connection.getTransaction().commit()
> finally:
>     connection.close()

Depends on what you're trying to achieve.  Best I can guess from this, it
would be simpler to do (this adds one line to your original example):

connection = db.open()
try:
    for each in connection.root()['mycollection']:
        each.setSomeState(arg)
    connection.getTransaction().commit()
finally:
    connection.getTransaction().abort()  # THE NEW LINE IS HERE
    connection.close()

As at the top, you're always "in" a transaction, and the instant commit()
returns you're in a new transaction too.  It doesn't hurt to abort() that
transaction (i.e., in the case where no exceptions are raised, it does no
harm to do an abort() immediately after a successful commit()).

> The reason I am concerned about this is that I have a relatively large
> web based system using ZODB and I don't want the entire web server to go
> down just because one of the web pages has a bug in it. Maybe one should
> always do connection.getTransaction().abort() before closing the
> connection?

If you judge that it's acceptable that your app may throw away attempted
modifications as a result, that's fine.  What I don't see in any of your
examples is "the usual" pattern:  a loop that explicitly catches conflict
errors, and then retries a failing transaction.  Some people would say that
Zope is also a relatively large web based system using ZODB that doesn't
want to go down just because a web page has a bug in it, and that's what it
does <wink>.  All the examples above still *appear* to allow the whole app
to go down if a conflict error occurs (because there's no code in them to
catch, deal with, and suppress conflict errors).



More information about the ZODB-Dev mailing list