[Stackless] Stackless + Twisted with deferred operations

Carlos Eduardo de Paula carlosedp at gmail.com
Tue Mar 13 15:05:10 CET 2007


Hi Greg, great suggestion and fix for it, with your code I improved
the blockOn function and added a timeout feature to it.

def blockOn(d, timeout=999):
    """
    Use me in stacklessy-code to wait for a Deferred to fire.
    If the result is an failure, send the exception via the channel
    to be captured by the tasklet.
    The timeout parameter is passed in seconds, defaults to 999 seconds
    and returns an exception.
    """
    ch = NWChannel()
    me = stackless.getcurrent()
    def goodCB(r, me, return_channel):
        cancelTimeout()
        return_channel.send_nowait(r)
        # if the deferred is called back immediately, this function
will be called
        # from the original tasklet. no need to reschedule.
        if stackless.getcurrent() != me:
            stackless.schedule()

    def badCB(f, me, return_channel):
        cancelTimeout()
        return_channel.send_exception_nowait(f.type, f.value)
        # if the deferred fails immediately, this function will be called
        # from the original tasklet. no need to reschedule.
        if stackless.getcurrent() != me:
            stackless.schedule()

    def onTimeout(me, return_channel):
        return_channel.send_exception_nowait("TimeoutException",
"Defer Timeout")
        if stackless.getcurrent() != me:
            stackless.schedule()

    def cancelTimeout():
        if delayedCall.active():
           delayedCall.cancel()

    delayedCall = reactor.callLater(timeout, onTimeout, me, ch)
    d.addCallback(goodCB, me, ch)
    d.addErrback(badCB, me, ch)
    return ch.receive()



With this we can have a timeout function to be called... its within
the specifications of Twisted since defer.setTimeout is deprecated.
For my example I do something like this:

        try:
            reactor.connectTCP("localhost", 8800, factory)
            def1 =
factory.login(credentials.UsernamePassword(self.login, self.pwd))
            self.perspective = blockOn(def1)
        except ConnectionRefusedError, val:
            print "Connection could not be opened."
            exit()
        except "TimeoutException":
               print "Timeout exception"
               exit()
        except:
            print "MISC ERROR"
            exit()



I will update the examples in the repository, if anyone have any other
improvement just send it out...

Carlos


On 3/12/07, Greg Hazel <greg at bittorrent.com> wrote:
>
> > def blockOn(d):
> >    """
> >    Use me in stacklessy-code to wait for a Deferred to fire.
> >    If the result is an failure, send the exception via the channel
> >    to be captured by the tasklet.
> >    """
> >    ch = stackless.channel()
> >    def cbOK(r):
> >        ch.send(r)
> >    def cbNOK(r):
> >        ch.send_exception(r.type, r.value)
> >    d.addCallbacks(cbOK, cbNOK)
> >    return ch.receive()
>
>
> The problem with this, and the purpose for NWChannel, is that
> d.addCallbacks() could call either of the callbacks immediately, causing a
> block before ch.reveive() is run. Try it: blockOn(defer.succeed(1))
> Using NWChannel, you can make a more robust blockOn like this (with 'good'
> and 'bad' from the example):
>
> def blockOn(df):
>    """
>    Use me in stacklessy-code to wait for a Deferred to fire.
>    If the result is an failure, send the exception via the channel
>    to be captured by the tasklet.
>     """
>    ch = NWChannel()
>    me = stackless.getcurrent()
>    df.addCallback(good, me, ch)
>    df.addErrback(bad, me, ch)
>    return ch.receive()
>
> -Greg

_______________________________________________
Stackless mailing list
Stackless at stackless.com
http://www.stackless.com/mailman/listinfo/stackless



More information about the Stackless mailing list