[Twisted-Python] deferring result to PB a callRemote method

Andrew Bennetts andrew at bemusement.org
Mon Jan 18 20:19:01 EST 2010


Chris Laws wrote:
[...]
>    I think the simple answer to my question is to just return a deferred as
>    the result to the callRemote("shutdown")�method and trigger it as normal.

Yes, that's right.  You can return Deferreds from your PB server's methods.  So
long as the eventual result is something serializable over PB (e.g. a
Referenceable or a Copyable), it will work.

>    Google is my friend but I could not find examples of this usage. Is there
>    any references to this usage in the twisted docs?

Huh, surprisingly not in the primary PB docs.  The Twisted “finger” tutorial
does do this, though, if you read it carefully enough.  See finger21.tac in
<http://twistedmatrix.com/documents/current/core/howto/tutorial/pb.html>; the
remote_* methods of PerspectiveFingerFromService delegate to self.service, which
is FingerService, which returns Deferreds from its getUser and getUsers methods.

[...]
>    Is the following code snippet the standard/normal way to defer the return
>    result of a callRemote method call?

It's a bit odd.  e.g. You do this:

    def remote_shutdown(self):
        """ Instruct Plugin to shutdown """
        print "plugin instructed to shutdown"
        d = defer.Deferred()
        self.shutdownHandler(d)
        return d

This can work, so long as on what self.shutdownHandler calls d.callback/errback,
as yours does.  But typically it would be written as:

    def remote_shutdown(self):
        """ Instruct Plugin to shutdown """
        print "plugin instructed to shutdown"
        return self.shutdownHandler()

i.e. typically the code that is calling d.callback is also responsible for
creating d.

>    If this is the normal way, how does triggering the deferred on the plugin
>    (client) side also trigger the same/copy deferred returned to the
>    plugin-runner (server)?
>    Is this PB magic, somehow managing deferreds across the PB interface?

PB doesn't actually send the Deferred over the network, but it does manage the
deferred for you.  It works because when you return a Deferred, PB on the server
will add a callback to it that will send that eventual result over the network,
rather than sending one immediately.

On the client side, as the PB docs point out: “because of the delay involved
[waiting for a network connection], callRemote() returns a Deferred.”  (From
<http://twistedmatrix.com/documents/current/core/howto/pb-usage.html>).

The client doesn't know or care if the server used a Deferred or not, the bytes
on the wire are the same.  (And a delay caused by the server waiting for a
Deferred to fire could just as easily be a delay caused by network congestion.)

I wouldn't describe it as “magic” so much as “a really convenient API”.

-Andrew.




More information about the Twisted-Python mailing list