[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