2

Suppose I have mynamespace.myproduct:

 <subscriber for="..interfaces.myinterface.IMyInterface
                  Products.CMFCore.interfaces.IActionSucceededEvent" 
            handler=".handlers.actionSucceeded" 
    /> 

and mynamespace.myproduct2:

 <subscriber for="..interfaces.myinterface.IMyInterface
                  Products.CMFCore.interfaces.IActionSucceededEvent" 
            handler=".handlers.actionSucceeded" 
    /> 

(the handlers do different stuff, on each product, even if they have the same name on this example)

I have a custom type that has a custom workflow. I'm going to do a workflow transition from Python, using doActionFor, and do a bunch of things when IActionSucceededEvent is triggered.

My question is: if I raise an exception on any of .handlers.actionSucceeded if an error occurs, will the doActionFor call be reverted (even after IActionSucceededEvent was run)? If not, if I use IActionWillBeInvokedEvent, will I be able to accomplish my goals? Will I have a problem for having two different products, both using Products.CMFCore.interfaces.IActionSucceededEvent for the same ..interfaces.myinterface.IMyInterface interface?

Lennart Regebro
  • 167,292
  • 41
  • 224
  • 251

3 Answers3

4
  1. Yes, if you raise any exception in one of your handlers the entire transaction will fail and it will be reverted
  2. no, you wouldn't have problems using more than one subscriber for the same interfaces. They would be execute in order of registration.
  3. no, using IActionWillBeInvokedEvent will not help. It's fired before wf transition, but if you raise exceptions the transaction will fail anyway.
Giacomo Spettoli
  • 4,476
  • 1
  • 16
  • 24
3

You can check this by turning Plone debug level to DEBUG (default is info) and put logging output to the event handlers. In DEBUG logging Plone prints transaction boundaries.

If your exception causes "505 Internal Server error" when the exception is raised it will also unroll any on-going transaction (unless transaction.commit() is called manually, but that should not be the case for the normal code).

Mikko Ohtamaa
  • 82,057
  • 50
  • 264
  • 435
  • Interesting about the DEBUG logging, I wasn't aware of the transaction boundaries. I testet calling `raise` in the event handlers, and indeed the transaction was aborted, but I was afraid I was doing something really hackish and wrong... :/ – Somebody still uses you MS-DOS Sep 05 '11 at 22:09
3

As per @Giacomo's response, the transaction will be aborted for any exception that isn't caught. So your best bet is to find out what errors you want to tolerate and catch those exceptions in your subscriber, log the exception, and then move on so the transaction will still be committed:

import logging
logger = logging.getLogger('mynamespace.myproduct')
...
def actionSucceeded(obj, event):
    ...
    try:
        my_dangerous_stuff(...)
    except (TolerableException, AnotherTolerableException, ...):
        logger.exception('Encountered an error while handling foo event')
    ...
Ross Patterson
  • 5,702
  • 20
  • 38