2009-07-02 14 views
7

Ho un'applicazione che esegue Twisted avviando il reattore con reactor.run() nella mia discussione principale dopo aver avviato alcuni altri thread, incluso il server Web CherryPy. Ecco un programma che si chiude in modo pulito quando viene premuto Ctrl + C su Linux, ma non su Windows:CherryPy interferisce con Arresto torto su Windows

from threading import Thread 
from signal import signal, SIGINT 

import cherrypy 

from twisted.internet import reactor 
from twisted.web.client import getPage 

def stop(signum, frame): 
    cherrypy.engine.exit() 
    reactor.callFromThread(reactor.stop) 
signal(SIGINT, stop) 

class Root: 
    @cherrypy.expose 
    def index(self): 
     reactor.callFromThread(kickoff) 
     return "Hello World!" 

cherrypy.server.socket_host = "0.0.0.0" 
Thread(target=cherrypy.quickstart, args=[Root()]).start() 

def print_page(html): 
    print(html) 

def kickoff(): 
    getPage("http://acpstats/account/login").addCallback(print_page) 

reactor.run() 

Credo che CherryPy è il colpevole qui, perché qui c'è un programma diverso che ho scritto senza CherryPy che fa l'arresto in modo pulito sia su Linux e Windows quando viene premuto Ctrl + C:

from time import sleep 
from threading import Thread 
from signal import signal, SIGINT 

from twisted.internet import reactor 
from twisted.web.client import getPage 

keep_going = True 
def stop(signum, frame): 
    global keep_going 
    keep_going = False 
    reactor.callFromThread(reactor.stop) 
signal(SIGINT, stop) 

def print_page(html): 
    print(html) 

def kickoff(): 
    getPage("http://acpstats/account/login").addCallback(print_page) 

def periodic_downloader(): 
    while keep_going: 
     reactor.callFromThread(kickoff) 
     sleep(5) 

Thread(target=periodic_downloader).start() 
reactor.run() 

qualcuno ha idea di quale sia il problema? Ecco il mio dilemma:

  • Su Linux tutto funziona
  • Su Windows, posso chiamare funzioni da gestori di segnale utilizzando reactor.callFromThread quando CherryPy non è in esecuzione
  • Quando CherryPy è in esecuzione, nessuna funzione che ho chiamata utilizzando reactor.callFromThread da un gestore di segnale verrà mai eseguito (ho verificato che il gestore di segnale stesso viene chiamato)

Cosa posso fare a questo proposito? Come posso chiudere Twisted su Windows da un gestore di segnale durante l'esecuzione di CherryPy? È un bug o ho semplicemente dimenticato una parte importante della documentazione per uno di questi due progetti?

risposta

14

CherryPy gestisce i segnali per impostazione predefinita quando si chiama quickstart. Nel tuo caso, dovresti probabilmente srotolare quickstart, che è solo poche righe, e scegliere. Ecco fondamentalmente quello QuickStart fa in tronco:

if config: 
    cherrypy.config.update(config) 

tree.mount(root, script_name, config) 

if hasattr(engine, "signal_handler"): 
    engine.signal_handler.subscribe() 
if hasattr(engine, "console_control_handler"): 
    engine.console_control_handler.subscribe() 

engine.start() 
engine.block() 

Nel tuo caso, non occorre i gestori di segnale, in modo da poter omettere quelle. Inoltre, non è necessario chiamare engine.block se non si avvia CherryPy dal thread principale. Engine.block() è solo un modo per far sì che il thread principale non si interrompa immediatamente, ma invece attendere la fine del processo (è così che il caricamento automatico funziona in modo affidabile, alcune piattaforme hanno problemi nel chiamare execv da qualsiasi thread ma il thread principale).

Se si rimuove la chiamata block(), non è nemmeno necessario il Thread() intorno all'avvio rapido. Quindi, sostituire la riga:

Thread(target=cherrypy.quickstart, args=[Root()]).start() 

con:

cherrypy.tree.mount(Root()) 
cherrypy.engine.start() 
+3

Grazie mille! La tua risposta è stata così ben scritta e utile che ho iniziato una taglia solo per darti 50 reputazione. –