[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