I am writing a tool for work that will run various software development aids such as message capturing and diagnostic control of system processes. My current design strategy is to implement these aids as plugins (not twisted plugins) to a generic plugin runner rather than stand alone applications. The plugins are spawned as separate processes by the plugin-runner and communicate using Perspective Broker during the plugin installation and shutdown phases.
Some plugins may take a while to shutdown as they need to close sockets, finalize files, move large files, etc. I would like to instruct the plugin to shutdown and be told when it is finally ready to be shut down. To date all my callRemote methods have effectively returned immediately. For example: def remote_get_name(self): return self.name My question to the list was going to be: Is there a pattern/example I could follow where I could call plugin.callRemote("shutdown") on a plugin and not return a result to the plugin-runner until the plugin has completed all it's, potentially, long running activities? However, while I was trying to write a small code snippet that would demonstrate what I was wanting, I think I got it working. 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. Google is my friend but I could not find examples of this usage. Is there any references to this usage in the twisted docs? Below (and attached in case the formatting goes screwy) is a short example which emulates a long running shutdown activity performed by the plugin prior to shutdown. It seems to delay the processing of the callRemote("shutdown") result until the plugin has completed it's long running activity. I have omitted the separate process stuff as it didn't seem relevant for this snippet. Is the following code snippet the standard/normal way to defer the return result of a callRemote method call? 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? Regards, Chris from twisted.internet import reactor, defer from twisted.spread import pb import datetime class PluginClient(pb.Referenceable): """ Plugin client interface exposed to PluginServer's """ def __init__(self, shutdownCallback): self.shutdownHandler = shutdownCallback def remote_shutdown(self): """ Instruct Plugin to shutdown """ print "plugin instructed to shutdown" d = defer.Deferred() self.shutdownHandler(d) return d class PluginServer(pb.Root): """ Plugin server interface exposed to PluginClient's """ def remote_set_client_perspective(self, pluginRef): print "plugin-runner got client reference" reactor.callLater(1.0, self.shutdown_plugin, pluginRef) def shutdown_plugin(self, pluginRef): def pluginShutdownCompleted(result, startTime): endTime = datetime.datetime.now() print "Plugin shutdown took %s to complete." % (endTime - startTime) return result print "plugin-runner asking plugin to shutdown" d = pluginRef.callRemote("shutdown") d.addCallback(pluginShutdownCompleted, datetime.datetime.now()) d.addCallback(self.shutdown) def shutdown(self, _): reactor.stop() def startPluginServer(port): """ Start a plugin communications server """ print "starting server" reactor.listenTCP(port=port, factory=pb.PBServerFactory(PluginServer()), interface='localhost') def startPluginClient(port, shutdownHandler): """ Start a plugin communications client """ def gotServerPerspective(serverPerspective, pluginPerspective): """ Give the plugin-runner this client's perspective """ serverPerspective.callRemote("set_client_perspective", pluginPerspective) return serverPerspective print "starting plugin" client = PluginClient(shutdownHandler) factory = pb.PBClientFactory() reactor.connectTCP(host='localhost', port=port, factory=factory) return factory.getRootObject().addCallback(gotServerPerspective, client) if __name__ == "__main__": port = 42155 def longRunningAction(d, countDown=10): """ Emulate long running shutdown activities """ print "shuting down in %i seconds" % countDown if countDown == 0: d.callback(True) else: countDown -= 1 reactor.callLater(1, longRunningAction, d, countDown) # start plugin-runner reactor.callWhenRunning(startPluginServer, port) # start plugin reactor.callLater(2.0, startPluginClient, port, longRunningAction) reactor.run()
test_shutdown.py
Description: Binary data
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python