<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>