[Twisted-Python] Newbie question: can't get getProcessOutput to run from inside a listenTCP service call-back

I have a Python server using twisted which responds to pyAMF calls from Flex/Air applications (following Bruce Eckels 5/1/2008 article "Concurrency with Python, Twisted, and Flex"). The service is basically as follows below. When the client calls a service API, the API needs to make a OS shell call. I see that if I call reactor.stop() after the getProcessOutput call (such as within the doLog and doError functions), the call happens and I see the output. How can can I retrieve the output without calling reactor.stop()? In the example below, the AIR app calls the callback helloWorldTest(), and the deferred.addCallback function is never called. import os from twisted.spread import pb from twisted.internet.utils import getProcessOutput from twisted.internet import reactor class FlexInterface(pb.Root): def __init__(self): self.result e def doLog(self, result): self.result = "%s" % (result) return result def doError(self, failure): self.result = "%s" % ( failure) return failure def helloWorldTest(self): deferred = getProcessOutput("echo", ["Hello World"], os.environ) deferred.addErrback(self.doError) deferred.addCallback(self.doLog) while (self.result == None) print "doLog still hasn't been called" return self.result def terminate(self, discardPostAag): reactor.callLater(1, reactor.stop) return "Terminating CubeGlyphServices" def run(): # Place the namespace mapping into a TwistedGateway: fi = FlexInterface() gateway = TwistedGateway({ "flexAppServer": fi }) # Publish the PyAMF gateway at the root URL: root = resource.Resource() root.putChild("", gateway) # Tell the twisted reactor to listen: reactor.listenTCP(8050, server.Site(root)) print "Local python server listening on localhost port 8050" reactor.run() if __name__=='__main__': run() I do know that If I used Python 2.6 and later, a twisted bug is fixed such that I could use subprocess.Popen, and that the next release of AIR will allow direct execv calls. However, for performance issues I still want to call one Python process running a server, and I have to work within a Python 2.5 environment. Thanks for any advice, Read Roberts

On 17 Oct 2009, at 05:15, Read Roberts wrote:
I have a Python server using twisted which responds to pyAMF calls from Flex/Air applications (following Bruce Eckels 5/1/2008 article "Concurrency with Python, Twisted, and Flex"). The service is basically as follows below. When the client calls a service API, the API needs to make a OS shell call. I see that if I call reactor.stop() after the getProcessOutput call (such as within the doLog and doError functions), the call happens and I see the output. How can can I retrieve the output without calling reactor.stop()? In the example below, the AIR app calls the callback helloWorldTest(), and the deferred.addCallback function is never called.
import os from twisted.spread import pb from twisted.internet.utils import getProcessOutput from twisted.internet import reactor
class FlexInterface(pb.Root): def __init__(self): self.result e
def doLog(self, result): self.result = "%s" % (result) return result
def doError(self, failure): self.result = "%s" % ( failure) return failure
def helloWorldTest(self): deferred = getProcessOutput("echo", ["Hello World"], os.environ) deferred.addErrback(self.doError) deferred.addCallback(self.doLog) while (self.result == None) print "doLog still hasn't been called" return self.result
The while loop will block the event loop, preventing the deferred from ever being called. PyAMF will accept a deferred as a return value for the service function and will not return a response until the deferred's callback is fired. So, you could re-write the method like: def helloWorldTest(self): deferred = getProcessOutput("echo", ["Hello World"], os.environ) deferred.addErrback(self.doError) deferred.addCallback(self.doLog) return deferred If the deferred's callback is called then the return value of doLog will be used as the response value. If the errback is called, the return value of doError will be used as the response, in this case a Failure instance. PyAMF converts Failure instances to remoting/ messaging error objects automagically, so the faultHandler on the flash/air side will be called. hth, Nick

Hi Nick; Thanks for the answer. However, If I take the while loop out, "helloWorldTest()" returns immediately, and the Flex app gets the initial value of self.result. The defer.callback function doLog never gets called. If I call the "terminate()" from the Flex app, which in turn calls reactor.sop() the doLog function finally then gets called. I am looking for what I need to do to allow getProcessOutput to run such that the defer.callback function doLog actually gets called. I have figured out that if instead of calling getProcessOutput() directly within the helloWorldTest() method, that I can queue it for running after helloWorldTest() as returned, as in: reactor.callLater(1, self. helloWorldTest2) and that the defer.callback function doLog does then get called. This means that the defer.callback function doLog will get called after the helloWorldTest() has returned. I see can call helloWorldTest() , and then keep querying the python service from the Flex app until the defer.callback function doLog has run. I still don't understand why calling getProcessOutput() directly within the helloWorldTest() method doesn't work. Any explanation would be welcome. Thanks, Read Roberts On 10/17/09 1:53 AM, "Nick Joyce" <nick@boxdesign.co.uk> wrote: On 17 Oct 2009, at 05:15, Read Roberts wrote:
I have a Python server using twisted which responds to pyAMF calls from Flex/Air applications (following Bruce Eckels 5/1/2008 article "Concurrency with Python, Twisted, and Flex"). The service is basically as follows below. When the client calls a service API, the API needs to make a OS shell call. I see that if I call reactor.stop() after the getProcessOutput call (such as within the doLog and doError functions), the call happens and I see the output. How can can I retrieve the output without calling reactor.stop()? In the example below, the AIR app calls the callback helloWorldTest(), and the deferred.addCallback function is never called.
import os from twisted.spread import pb from twisted.internet.utils import getProcessOutput from twisted.internet import reactor
class FlexInterface(pb.Root): def __init__(self): self.result e
def doLog(self, result): self.result = "%s" % (result) return result
def doError(self, failure): self.result = "%s" % ( failure) return failure
def helloWorldTest(self): deferred = getProcessOutput("echo", ["Hello World"], os.environ) deferred.addErrback(self.doError) deferred.addCallback(self.doLog) while (self.result == None) print "doLog still hasn't been called" return self.result
The while loop will block the event loop, preventing the deferred from ever being called. PyAMF will accept a deferred as a return value for the service function and will not return a response until the deferred's callback is fired. So, you could re-write the method like: def helloWorldTest(self): deferred = getProcessOutput("echo", ["Hello World"], os.environ) deferred.addErrback(self.doError) deferred.addCallback(self.doLog) return deferred If the deferred's callback is called then the return value of doLog will be used as the response value. If the errback is called, the return value of doError will be used as the response, in this case a Failure instance. PyAMF converts Failure instances to remoting/ messaging error objects automagically, so the faultHandler on the flash/air side will be called. hth, Nick _______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
participants (2)
-
Nick Joyce
-
Read Roberts