ZODB & Zope 2.8 ZRDB/TM : "raise" + "except: pass"
Hi. I triggered a bad behaviour in Zope 2.8 Transaction class: try: <do something> <commit> <- raises conflict error from ZODB's tpc_vote except: <cleanup> raise Here, <cleanup> uses a transaction-registered connection which is not used before, hence not registered to transaction manager. So that connection tries to register by calling Shared/DC/ZRDB/TM.py:TP._register. Which ends up calling "join" on a status = Status.COMMITFAILED transaction, which raises TransactionFailedError in _prior_operation_failed. Note that before raising, Transaction.register did adapter.objects.append(obj) The raise is caught in TM._register, which prevents it from setting self._registered = 1 A second use of the connection will cause TM to call Transaction.register again because if not self._registered: evaluates to True. But this time, Transaction.register will not raise, since if adapter is None: now evaluates to False. As it does not raise, TM will set self._registered = 1 So now there is a connection which is set as registered, but which will not be commited nor aborted by transaction. Worse, as TM checks self._registered before registering to transaction, the connection will never be registered again. -- Vincent Pelletier
Pelletier Vincent wrote:
Hi.
I triggered a bad behaviour in Zope 2.8 Transaction class:
You might be better off asking about this on zodb-dev@zope.org. Also, try and make it a bit clearer about what you'd like help with... I did scan this but couldn't actually see any indication of what you wanted help with... cheers, Chris -- Simplistix - Content Management, Zope & Python Consulting - http://www.simplistix.co.uk
Pelletier Vincent wrote at 2008-2-8 10:56 +0100:
I triggered a bad behaviour in Zope 2.8 Transaction class:
try: <do something> <commit> <- raises conflict error from ZODB's tpc_vote except: <cleanup>
Where does this "cleanup" code comes from -- from your application?
raise
"try: ... except: ..." are extremely dangerous -- never use them. If you think you need something like this, always use try: ... except ConflictError: raise except: ....
... Note that before raising, Transaction.register did adapter.objects.append(obj)
In my Zope 2.8.1, this does not happen -- probably a bug that has been introduced later. I would check whether the problematic code is still in the current Zope version. If so, I would file a bug report. Otherwise, you may consider an upgrade or a local fix. -- Dieter
(woops, forgot to cc the list when answering) Le Vendredi 8 Février 2008 22:41, vous avez écrit :
Where does this "cleanup" code comes from -- from your application?
Yes (explanation folows).
"try: ... except: ..." are extremely dangerous -- never use them.
If you think you need something like this, always use
try: ... except ConflictError: raise except: ....
What it does with more details is: - fetch a task from a task list and put it in "being processed" state - execute the task - update the task list: delete task if successfull, otherwise put it back to a "pending" state Task execution request is generated by timerserver. Tasks are executed in a loop (no need to wait for next timerserver poll if application knows it still have tasks to process), and to make a task's result independant from other tasks' success, I must commit/abort during the transaction depending on task success. So I need to intercept conflict error from the "execute the task" phase, otherwise I will get tasks in a "being processed" state, causing them to stall untill state gets fixed by hand. As task list is shared among multiple Zope instances (to paralelize task execution) I need to make modifications to this list visible to other nodes as soon as possible, to prevent multiple nodes from processing the same task. All suggestions improving those design choices are welcome.
In my Zope 2.8.1, this does not happen -- probably a bug that has been introduced later.
Mmh, the code was here from revision 3436, which is an initial import: http://svn.zope.org/ZODB/trunk/src/transaction/_transaction.py?rev=3436&view... (see below "def register") Note that the problem was triggered by a bug in my application: I was trying to use a connection not yet registered with transaction manager after the transaction failed to commit and before aborting it... Transaction class does detect this as a problem, but only after modifying its data (the "append" I mentioned). And it is worsened by TM hiding the exception raised in Transaction.
I would check whether the problematic code is still in the current Zope version. If so, I would file a bug report.
Code I think should be canged is still in Zope 2 trunk (TM.py), and still in transaction trunk (_transaction.py), so I'll bugreport. -- Vincent Pelletier
participants (3)
-
Chris Withers -
Dieter Maurer -
Pelletier Vincent