system.multicall support for the XML-RPC server
Hello, The Twisted XML-RPC server does not come with system.multicall, a de facto standard method which allows a batch of methods to be called in a single request. I wrote an implementation which handles deferred results and ensures that exceptions in one method call do not prevent the other methods from executing. I had to add to the XMLRPCIntrospection class in order to include my method in the system namespace, even though it is not really an introspection method. It's also possible to subclass XMLRPCIntrospection from outside of xmlrpc.py and use putSubHandler instead of xmlrpc.addIntrospection to create the "system" namespace. Anyhow, let me know what you think. Patch follows. Thanks for making Twisted such a joy to read and use. Dave --- /usr/share/pyshared/twisted/web/xmlrpc.py 2008-09-05 02:18:26.000000000 -0700 +++ xmlrpc.py 2009-05-01 10:58:39.000000000 -0700 @@ -246,6 +246,33 @@ xmlrpc_methodSignature.signature = [['array', 'string'], ['string', 'string']] + def xmlrpc_multicall(self, calls): + """ + Boxcar multiple RPC calls in one request. + """ + results = [] + for call in calls: + name = call['methodName'] + params = call['params'] + method = self._xmlrpc_parent._getFunction(name) + try: + d = defer.maybeDeferred(method, *params) + g = defer.waitForDeferred(d) + yield g + result = [g.getResult()] + except Fault, f: + result = {'faultCode': f.faultCode, + 'faultString': f.faultString} + except Exception, e: + log.err(e) + result = {'faultCode': self.FAILURE, + 'faultString': 'error'} + results.append(result) + yield results + + xmlrpc_multicall = defer.deferredGenerator(xmlrpc_multicall) + xmlrpc_multicall.signature = [['array', 'array']] + def addIntrospection(xmlrpc): """
On 1 May, 06:29 pm, dave@ramenlabs.com wrote:
Hello,
Hi Dave! Thanks for taking the time to contribute. Unfortunately, this contribution will almost certainly be lost if you don't open a ticket for it at <http://twistedmatrix.com/trac/newticket>. Once you've done that, you'll need to mark it for review by adding the "review" keyword and reassigning it to nobody - the empty entry at the top of the "reassign" menu. More information on our development process is here: http://twistedmatrix.com/trac/wiki/TwistedDevelopment I'll give you the first round of review on the list, though :).
The Twisted XML-RPC server does not come with system.multicall, a de facto standard method which allows a batch of methods to be called in a single request.
Can you include a reference in the docstrig to some document describing this standard, even if it's just a blog post or a wiki page somewhere explaining its expected semantics?
I had to add to the XMLRPCIntrospection class in order to include my method in the system namespace, even though it is not really an introspection method. It's also possible to subclass XMLRPCIntrospection from outside of xmlrpc.py and use putSubHandler instead of xmlrpc.addIntrospection to create the "system" namespace.
I'm not quite sure what you're getting at here - do you think one of these other approaches would be better!
Anyhow, let me know what you think. Patch follows. Thanks for making Twisted such a joy to read and use.
Thanks for contributing! The first and most important thought I have about this patch is that sadly, it does not include any unit tests. Our development process mandates that all new features have complete test coverage. Ideally new features would all be developed in a test-driven way. If you need some help with that, you're in luck. There's a Twisted sprint tomorrow (Saturday, May 2). If you're in the vicinity of Cambridge, MA, you can drop by the Divmod office and join us physically; otherwise, join us in the #twisted IRC channel on chat.freenode.net.
--- /usr/share/pyshared/twisted/web/xmlrpc.py 2008-09-05 02:18:26.000000000 -0700 +++ xmlrpc.py 2009-05-01 10:58:39.000000000 -0700 @@ -246,6 +246,33 @@
Just looking at this information in the diff here; the best way to generate diffs for contribution is to have a checkout of current SVN trunk and run 'svn diff' at the root. Generating diffs against your system installation of Twisted is problematic for many reasons. For one thing, it makes them harder to apply to the most recent code. For another, ubuntu and debian's versions of Twisted can diverge from the version that we distribute, sometimes substantially, since they apply their own patches.
xmlrpc_methodSignature.signature = [['array', 'string'], ['string', 'string']]
+ def xmlrpc_multicall(self, calls): + """ + Boxcar multiple RPC calls in one request. + """
It would be helpful if you included a "@param" describing the expected structure of "calls" here, in addition to the description of this de- facto standard. As it is, I have to puzzle it out from .signature below and the body of the method.
+ results = [] + for call in calls: + name = call['methodName'] + params = call['params'] + method = self._xmlrpc_parent._getFunction(name) + try: + d = defer.maybeDeferred(method, *params) + g = defer.waitForDeferred(d) + yield g + result = [g.getResult()] + except Fault, f: + result = {'faultCode': f.faultCode, + 'faultString': f.faultString} + except Exception, e: + log.err(e) + result = {'faultCode': self.FAILURE, + 'faultString': 'error'} + results.append(result) + yield results + + xmlrpc_multicall = defer.deferredGenerator(xmlrpc_multicall)
By using deferredGenerator here, you're eliminating any possible parallelism and forcing all of the requests to happen in serial, even if they're deferred. Is that intentional? It looks like this would be better written as a normal Deferred-using function.
+ xmlrpc_multicall.signature = [['array', 'array']] +
def addIntrospection(xmlrpc): """
_______________________________________________ Twisted-web mailing list Twisted-web@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-web
participants (2)
-
Dave Benjamin
-
glyph@divmod.com