multithreading - How to (repeatedly) create and shut down multiple instances of python twisted factory / reactor? -
firstly, apologies title thread - worded better, i'm not sure know how! anyway...
i have following methods start, , stop smtp server respectively:
# ----------------------------------------------------------------------- def startserver(configname = 'default'): try: svrcfg = getserverconfig(configname) startlogger (svrcfg.find('logfile').text) portal = portal(simplerealm()) checker = inmemoryusernamepassworddatabasedontuse() checker.adduser("guest", "password") portal.registerchecker(checker) serverport = int(svrcfg.find('port').text) reactor.listentcp(serverport, consolesmtpfactory((portal, svrcfg))) thread(target=reactor.run, args=(false,)).start() # reactor.run() except twisted.internet.error.cannotlistenerror, e: errstring = "cannot start server, port " + svrcfg.find('port').text + " busy" log.msg (errstring, loglevel=logging.critical) except: log.msg ("unknown error", loglevel=logging.critical) # ----------------------------------------------------------------------- def stopserver(): reactor.callfromthread(reactor.stop) # -----------------------------------------------------------------------
the long term plan startserver
, stopserver
robotframework
keywords. though, of course sufficient go python command line, import source module (mailserver.py
) , "mailserver.startserver()
" or "mailserver.stopserver()"
etc. fine starting server first time, , stopping it.
however want able start / stop multiple, concurrent mailservers, listening on different ports - example, mailserver.startserver("p25")
mailserver.startserver("p26")
, mailserver.stopserver("p25")
start 2 instances, shut first 1 down.
even existing code, restarting "default" listener fails reactornotrestartable error... , of course, starting "default" listener, starting "p26" listener results in "reactoralreadyrunning" error.
can offer advice on how around these errors? firstly, how multiple listeners, , secondly, how specify 1 shut down part of "stopserver"?
(incidentally, using thread allow startserver exit next robotframework keyword execute...)
many thanks
edit - following @jeanpaul-calderone 's answer... i've managed create following:
so i've tweaked code support adding / removing listeners, below:
def addlistener(configname = 'default'): try: svrcfg = getserverconfig(configname) startlogger (svrcfg.find('logfile').text) portal = portal(simplerealm()) checker = inmemoryusernamepassworddatabasedontuse() checker.adduser("guest", "password") portal.registerchecker(checker) serverport = int(svrcfg.find('port').text) listenerport = reactor.listentcp(serverport, consolesmtpfactory((portal, svrcfg))) runninglisteners[configname] = listenerport print runninglisteners except twisted.internet.error.cannotlistenerror, e: errstring = "cannot start server, port " + svrcfg.find('port').text + " busy" log.msg (errstring, loglevel=logging.critical) except: log.msg ("unknown error", loglevel=logging.critical) # ----------------------------------------------------------------------- def stoplistener(configname = 'default'): listenerport = runninglisteners[configname] print listenerport listenerport.stoplistening() listenerport.connectionlost("closing listener requested") del runninglisteners[configname] # ----------------------------------------------------------------------- thread(target=reactor.run, args=(false,)).start() runninglisteners={}
i can add , remove multiple listeners... however, when tried (for debug purposes) ctrl-d python command line session, hung - had ctrl-z, , kill job.
so realised reactor had been left running, added:
def stopreactor(): reactor.callfromthread(reactor.stop)
but when ctrl-d python session:
unhandled error in deferred: unhandled error traceback (most recent call last): file "/usr/local/lib/python2.7/site-packages/twisted/internet/base.py", line 1201, in mainloop self.rununtilcurrent() file "/usr/local/lib/python2.7/site-packages/twisted/internet/base.py", line 824, in rununtilcurrent call.func(*call.args, **call.kw) file "/usr/local/lib/python2.7/site-packages/twisted/internet/defer.py", line 382, in callback self._startruncallbacks(result) file "/usr/local/lib/python2.7/site-packages/twisted/internet/defer.py", line 490, in _startruncallbacks self._runcallbacks() --- <exception caught here> --- file "/usr/local/lib/python2.7/site-packages/twisted/internet/defer.py", line 577, in _runcallbacks current.result = callback(current.result, *args, **kw) file "/usr/local/lib/python2.7/site-packages/twisted/internet/task.py", line 832, in <lambda> d.addcallback(lambda ignored: callable(*args, **kw)) file "/usr/local/lib/python2.7/site-packages/twisted/internet/tcp.py", line 1115, in connectionlost self._closesocket(true) file "/usr/local/lib/python2.7/site-packages/twisted/internet/tcp.py", line 123, in _closesocket skt = self.socket exceptions.attributeerror: 'port' object has no attribute 'socket'
can advise getting wrong?
you can start twisted reactor once. if have multiple tasks want accomplish, need start reactor before first 1 , stop after last one. can't start , stop around each task.
you may find crochet helpful in managing reactor usage pattern.
Comments
Post a Comment