[Twisted-Python] Dealing with an intermittent PB server

Ken Kinder ken at kenkinder.com
Fri Feb 25 14:45:42 EST 2005

For what it's worth, I had a similar need and I don't pass objects 
around on PB (just data structures), so this class works out well for 
me. If the remote server isn't up or goes down, the returned deferred 
just waits. I tried to take out all the logic that relates to my 


class SimplePBProxy(object):
    A simple U{Perspective 
Broker<http://twistedmatrix.com/documents/current/howto/pb-intro>} proxy for
    remote servers. This works similar to the xmlrpc proxy, but uses 
        hostname = 'remotebox'
        pb_port = 5053
        proxy = SimplePBProxy(hostname, pb_port)
        deferred_object = proxy.callRemote('somecall')
    B{NOTE:} Unlike the default Perspective Broker behavior, this 
doesn't wig out
    if the connection is lost. Deferred objects simple won't be returned 
    the remote server comes back up. Likewise, if the remote server 
isn't yet up,
    the deferred will simply be held open until the remote box is up.
    def __init__(self, host, port):
        @param host: Host to connect to.
        @rtype host: String
        @param port: Port PB is on.
        @rtype port: Integer
        self.host = host
        self.port = port
        self.pending_calls = []

        self.rootobj = None

    def connect(self):
        Used internally. Connects to remote server.
        def handle_error(failure):
            reactor.callLater(1, self.connect)
        factory = pb.PBClientFactory()
        factory.unsafeTracebacks = 1
        reactor.connectTCP(self.host, self.port, factory)
        d = factory.getRootObject()
        return d

    def _set_root_object(self, rootobj):
        self.rootobj = rootobj
        def pending_act(data, deferred):
        def pending_err(failure, deferred):

        for deferred, method, args, kwargs in self.pending_calls:
            d = self.callRemote(method, *args, **kwargs)
            d.addCallback(pending_act, deferred)
            d.addErrback(pending_err, deferred)
        self.pending_calls = []

    def callRemote(self, method, *args, **kwargs):
        Call method on remote API. Method is a string. Any additional 
        and keyword arguments are passed to that method as arguments and
        keyword arguments.
        if not self.rootobj:
            d = Deferred()
            self.pending_calls.append((d, method, args, kwargs))
            return d

            d = self.rootobj.callRemote(method, *args, **kwargs)
            d.addErrback(self._error_back, method, args, kwargs)
            return d
        except pb.DeadReferenceError:
            self.rootobj = None
            d = Deferred()
            self.pending_calls.append((d, method, args, kwargs))
            return d
    def _error_back(self, failure, method, args, kwargs):
        if failure.type is twisted.spread.pb.PBConnectionLost:
            self.rootobj = None
            d = Deferred()
            self.pending_calls.append((d, method, args, kwargs))
            return d
            return failure

Dave Cook wrote:

>I'm rendering the results of a remote method call:
>    def data_tableList(self, ctx, data):
>        ...
>        d =   self.pbClientFactory.login(creds)
>        d.addCallback(lambda object: object.callRemote("foo"))
>        return d
>Works, great if the PB server is up,  but if it's down the browser
>just hangs.  Is there a correct way to check that the connection is up
>at this point?  This works:
>       if self.pbClientFactory._broker:
>            d = self.pbClientFactory.login(creds)
>            d.addCallback(lambda object: object.callRemote("getAlertReports"))
>        else:
>            d = []
>        return d
>but seems like a hack.  Also, ideally, I'd like to attempt a
>reconnection to the PB server at this point if it's not running. 
>What's the best way to do that?
>Dave Cook
>Twisted-Python mailing list
>Twisted-Python at twistedmatrix.com

More information about the Twisted-Python mailing list