<div dir="ltr">Tom -<div><br></div><div>Just wanted to thank you for your help. I got everything ported over to Twisted on Friday, and the responsiveness of the web site is 10 times better. Also the number of lines of (my) code declined, which is great.</div>
<div><br></div><div>Thanks much.</div><div><br></div></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Wed, Aug 28, 2013 at 6:40 AM, Tom Sheffler <span dir="ltr"><<a href="mailto:tom.sheffler@gmail.com" target="_blank">tom.sheffler@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><br><div><div>Hi Matthew -</div><div><br></div><div>I have a couple of idioms I use for #2 and #3 in your message.  Here they are.</div>
<div><br></div><div>#2)</div><div><br></div><div>For timer events, I create a function that when called, continuously</div>
<div>schedules itself again in the reactor, does some work for the current</div><div>tick, and then exits.  I've used this down to 1-second intervals.  If</div><div>you're looking for sub-millisecond level timing, this may not be</div>

<div>appropriate for your application.</div><div><br></div><div>def timerFunction(reactor):</div><div><br></div><div>    reactor.callLater(1.0, timerFunction, reactor)</div><div><br></div><div>    # do the work for this time tick</div>

<div>    # etc etc</div><div><br></div><div>    return</div><div><br></div><div># Somewhere in main do this to kick it off</div><div>from twisted.internet import reactor</div><div>timerFunction(reactor)</div><div><br></div>

<div><br></div><div>#3)</div><div><br></div><div>For subprocesses, I like to create a custom protocol for each type of</div><div>sub-command I am calling.  I also like to create an object to manage</div><div>the process, its arguments, its results and its temp files.  The idiom</div>

<div>below is suitable for calling a subprocess that accepts a small amount</div><div>of buffered data on stdin, produces some output on stdout, and logs its</div><div>stderr.</div><div><br></div><div>Be careful examining the value of reason.value.exitCode in</div>

<div>processExited.  The twisted docs show printing the exitCode as a "%d",</div><div>but sometimes the value is None --- if the process was terminated by a</div><div>signal.  The mere printing of the value with "%d" will then trigger an</div>

<div>exception!</div><div><br></div><div><br></div><div>Here's my idiom:</div><div><br></div><div>class FooprocProtocol(protocol.ProcessProtocol):</div><div><br></div><div>    def __init__(self, foomgr):</div><div>        # the object managing my subprocess</div>

<div>        self.foomgr = foomgr</div><div><br></div><div>        # my stdout data</div><div>        self.data = ""</div><div><br></div><div>    def connectionMade(self):</div><div>        # Pump input data in using this, and then close stdin</div>

<div>        log.msg("connectionMade!")</div><div>        # self.transport.write("...")  # if there is any data to shove into stdin</div><div>        self.transport.closeStdin()</div><div><br></div><div>

    def outReceived(self, data):</div><div>        # collect up our stdout</div><div>        log.msg("outReceived! with %d bytes!" % len(data))</div><div>        self.data = self.data + data</div><div><br></div>

<div>    def errReceived(self, data):</div><div>        # echo stderr messages to log with a marker</div><div>        log.msg(">%s" % data)</div><div><br></div><div>    def inConnectionLost(self):</div><div>
        print "inConnectionLost! stdin is closed! (we probably did it)"</div>
<div><br></div><div>    def outConnectionLost(self):</div><div>        log.msg("outConnectionLost! The child closed their stdout!")</div><div><br></div><div>    def errConnectionLost(self):</div><div>        log.msg("errConnectionLost! The child closed their stderr.")</div>

<div><br></div><div>    def processExited(self, reason):</div><div>        log.msg("processExited:%s:" % reason)</div><div>        exitcode = reason.value.exitCode         # an integer or None</div><div><br></div>

<div>        # do some work upon processExit potentially make a decision on exitcode ...</div><div>        </div><div>        log.msg("processExited:%s" % exitcode)</div><div><br></div><div>    def processEnded(self, reason):</div>

<div>        print "processEnded, status %s" % (reason.value.exitCode,)</div><div><br></div><div>        # process the data in the process manager</div><div>        exitcode = reason.value.exitCode         # might be non-numeric</div>

<div>        result = self.foomgr.processData(exitcode)</div><div><br></div><div><br></div><div><br></div><div># The main job of the Process Manager is to build the command list and</div><div># process the results.  It gives us a handy place to encapsulate this</div>

<div># logic.</div><div><br></div><div>class FooprocManager(object):</div><div><br></div><div>    CMD = "/usr/local/foocmd"</div><div><br></div><div>    def __init__(self, arg1, arg2, arg3)</div><div><br></div>
<div>
        # create a Deferred to fire when we succeed or fail</div><div>        self.d = Deferred()</div><div><br></div><div>        # build our command argument list as appropriate for our command</div><div>        self.cmdargs = self.build_cmd_args(arg1, arg2, arg3)</div>

<div><br></div><div>        # define places to store the transport, pid and other things</div><div>        self.ptransport = None</div><div>        self.pid = None</div><div><br></div><div>    def build_cmd_args(self, arg1, arg2, arg3):</div>

<div><br></div><div>        # in my projects, this method has become fairly involved as it creates</div><div>        # tmp files and builds potentially complicated argument lists.</div><div><br></div><div>        arglist = [self.CMD, arg1, arg2, arg3]</div>

<div>        return arglist</div><div>        </div><div>    def run(self):</div><div><br></div><div>        # instantiate a protocol connected to this manager</div><div>        pp = FooprocProtocol(self)</div><div><br></div>

<div>        # spawn the process, save the PID</div><div>        self.ptransport = reactor.spawnProcess(pp, self.CMD, self.cmdargs, { })</div><div>        self.pid = self.ptransport.pid</div><div><br></div><div>    def processData(exitcode):</div>

<div><br></div><div>        # in my projects, this method opens up result files, parses results,</div><div>        # moves things around, deletes tmp files, etc.</div><div>        </div><div>        # return the result that we ran this subprocess for</div>

<div>        return result</div><div><br></div><div><br></div><div># Instantiate a new process manager and run it this way.</div><div><br></div><div>mgr = FooprocManager(args ...)</div><div>d = mgr.run(args ...)</div><div>

<br></div><div>    </div><div>=================</div></div><span class="HOEnZb"><font color="#888888"><div>T</div></font></span></div>
<br>_______________________________________________<br>
Twisted-Python mailing list<br>
<a href="mailto:Twisted-Python@twistedmatrix.com">Twisted-Python@twistedmatrix.com</a><br>
<a href="http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python" target="_blank">http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python</a><br>
<br></blockquote></div><br></div>