[Twisted-Python] Dealing with an intermittent PB server

Ken Kinder ken at kenkinder.com
Fri Feb 25 12:45:42 MST 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 
application.

-Ken

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 
Perspective
    Broker.
   
    Example::
       
        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 
until
    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
        self.connect()

    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()
        d.addCallback(self._set_root_object)
        d.addErrback(handle_error)
        return d

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

        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 
arguments
        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))
            self.connect()
            return d

        try:
            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))
            self.connect()
            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))
            self.connect()
            return d
        else:
            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?
>
>Thanks,
>Dave Cook
>
>_______________________________________________
>Twisted-Python mailing list
>Twisted-Python at twistedmatrix.com
>http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
>  
>





More information about the Twisted-Python mailing list