<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><div style>T</div></div>