[Twisted-Python] Question about RequestHandlers and inlinecallbacks

Jean-Paul Calderone exarkun at divmod.com
Thu Jan 24 17:31:11 EST 2008


On Thu, 24 Jan 2008 13:03:17 -0800 (PST), Andrew Francis <andrewfr_ice at yahoo.com> wrote:
>Hello Folks:
>
>I am starting to learn inlinecallbacks. I am trying to
>do the following:
>
>from within a RequestHandler, I get a web page with
>the client.getPage() method. I subsequently return the
>web page to the requesting web browser.
>
>The problem -
>
>The web browser hangs. However the
>requestHandler.writes are echoed to standard output
>(or error).

Well... almost.  Your attached example doesn't actually print out
what is passed to Request.write().  It prints out what is passed to
the callback of the Deferred returned by getPage.

>
>The problem is that in process(self), a deferred is
>created but process() ends finishes without outputting
>anything to the web browser.

As it must.  The output is the result of a network operation.  It is
exceedingly unlikely that it will be able to happen before process()
returns.

>
>Eventually, the associated callback is triggered but
>the request has already been serviced.

I'm not sure what this means.  What is "the associated callback"?

>
>What I really want is process() to wait until the
>client.getPage() is finished.

That's what Deferreds are for.  Whatever you want to happen after
client.getPage() has happened, you should put into a callback and
attach that callback to the Deferred you get (like you did with
gotPage, almost).

>
>What I am unclear about is how to properly structure
>the programme to get the appropriate behaviour. I am
>assuming this is possible. If so, what am I missing?

The part where you got confused is the part that uses inlineCallbacks,
I think.

You defined a gotPage callback which uses defer.returnValue.  This is
totally bogus.  If you want a callback to return a value, then you just
return it.  defer.returnValue lets you specify the result of a Deferred
returned by a call to a function decorated with inlineCallbacks.

Your gotPage function has not been so decorated, so there's your bug I
suspect.

What you want process() to look like is this:

    def process(self):
        pageDeferred = client.getPage(...)
        def gotPage(result):
            self.write(result)
            self.finish()
        def gotError(err):
            log.err(err, "process getPage call failed")
            self.finish()
        pageDeferred.addCallbacks(gotPage, gotError)

If you used inlineCallbacks, then it would look like this:

    def process(self):
        try:
            result = yield client.getPage(...)
        except Exception, err:
            log.err(err, "process getPage call failed")
        else:
            self.write(result)
        self.finish()
    process = inlineCallbacks(process)

Jean-Paul




More information about the Twisted-Python mailing list