On 30/09/2010 14:03, Phil Mayers wrote:
On 30/09/10 13:44, Phil Mayers wrote:

This is because (as you've discovered) there are circumstances when a
function is called in Twisted where the exception can't propagate "up"
to the caller, because the caller is no longer higher in the call stack.

Indeed, but, as I keep saying, I need to build a scheduler that's resilient to errors in the tasks its running ;-)

Most prominent is reactor.callLater.

...which I'm not actually using, it was just a small-as-possible way I could simulate the failure mode (rather than the specific failure) I need to protect against.

@inlineCallbacks
def loop():
    try:
      yield doStuff()
    except Exception, e:
      log.err(e)

...will then work, and "see" the exception.

Actually, what appears to work is simply changing `loop` to not be an async fuction:

def loop():
    try:
        doStuff()
    except Exception,e:
        log.err(None,'Unhandled scheduled exception')

looper = task.LoopingCall(loop)
looper.start(1.0)
reactor.run()

This appears to solve most of the problems:
- the schedule now keeps running regardless
- exceptions in doStuff and below get logged

However, it now has the problem that if doStuff *does* return a deferred and it errbacks, the I get the ugly:

2010-09-30 14:31:12,478 ERROR : log (22159|7fc6c5c356e0): Unhandled error in Deferred: 2010-09-30 14:31:12,479 ERROR : log (22159|7fc6c5c356e0): Unhandled Error
Traceback (most recent call last):
Failure: twisted.python.failure.DefaultException: Break!

...rather than having my exception handler log with a meaningful message.

I've attached the full example as I have it again...

Is there any way I can get both errbacks *and* exceptions handled nicely in my `loop` call?

cheers,

Chris
from datetime import datetime
from twisted.internet.defer import inlineCallbacks, maybeDeferred, fail, 
Deferred, succeed
from twisted.internet import task, reactor
from twisted.python import log
from twisted.python.log import PythonLoggingObserver, defaultObserver

import logging

defaultObserver.stop()
logging.basicConfig(level=0,
                    format=(
        "%(asctime)s %(levelname)-8s: %(module)-11s"
        " (%(process)d|%(thread)x): %(message)s"
        ))
observer = PythonLoggingObserver()
observer.start()

class Break:

    called = 0
    
    def __init__(self):
        self.deferred = Deferred()

    def __call__(self):
        self.__class__.called += 1
        print "called ",self.called
        if self.called==3:
            del self.connector
        if self.called==5:
            self.deferred.errback('Break!')
        else:
            self.deferred.callback('happy!')

def doStuff():
    b = Break()
    reactor.callLater(2,b)
    return b.deferred

def loop():
    try:
        doStuff()
    except Exception,e:
        log.err(None,'Unhandled scheduled exception')
    
looper = task.LoopingCall(loop)
looper.start(1.0)
reactor.run()
_______________________________________________
Twisted-Python mailing list
Twisted-Python@twistedmatrix.com
http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python

Reply via email to