2013-03-22 21 views
35

Chcę zaimplementować polecenie, które może zatrzymać aplikację kolby za pomocą skryptu kolby. Poszukałem rozwiązania na jakiś czas. Ponieważ framework nie udostępnia interfejsu API "app.stop()", jestem ciekawy jak to zakodować. Pracuję nad Ubuntu 12.10 i Python 2.7.3.Jak zatrzymać aplikację kolb bez użycia ctrl-c

+0

Dlaczego musisz mieć możliwość zatrzymania aplikacji ze skryptu? (Najlepsze narzędzie do pracy będzie zależeć od tego, co próbujesz zrobić). –

+0

Poważnie, co próbujesz tutaj zrobić? Jeśli mówisz o devserver dla rozwoju, to idealnie jest zatrzymać to tak. W produkcji nie wdrażasz w ten sposób i możesz zatrzymać żądanie w dowolnym momencie, więc "aplikacja przestaje działać". –

+0

@SeanVieira Chcę wiedzieć, czy są jakieś rozwiązania, aby to zrobić. – vrootic

Odpowiedz

44

Jeśli dopiero uruchomienie serwera na pulpicie, można narazić punkt końcowy, aby zabić serwer (czytaj więcej na Shutdown The Simple Server):

from flask import request 
def shutdown_server(): 
    func = request.environ.get('werkzeug.server.shutdown') 
    if func is None: 
     raise RuntimeError('Not running with the Werkzeug Server') 
    func() 

@app.route('/shutdown', methods=['POST']) 
def shutdown(): 
    shutdown_server() 
    return 'Server shutting down...' 

Oto inne podejście, które jest bardziej zawierała:

from multiprocessing import Process 

server = Process(target=app.run) 
server.start() 
# ... 
server.terminate() 
server.join() 

Daj mi znać, jeśli to pomoże.

+8

Czy wiesz, czy istnieje sposób uzyskania właściwości "werkzeug.server.shutdown" bez kontekstu żądania? – akatkinson

+1

Musiałem zmienić metodę trasy na "GET", aby ją uruchomić. –

+2

Dla kompletności w tej odpowiedzi brakuje funkcji, którą wywołasz poza kontekstem żądania, aby wykonać wyłączenie, które byłoby niczym więcej niż żądanie HTTP do serwera (które może pochodzić z/do localhost) – JamesHutchison

4

Jak zauważyli inni, można użyć tylko werkzeug.server.shutdown z procedury obsługi żądań. Jedynym sposobem, w jaki udało mi się zamknąć serwer w innym momencie, jest wysłanie prośby do siebie. Na przykład, przewodnik w tym fragmencie /kill zabije serwer dev chyba że inny wniosek jest w trakcie następnej sekundzie:

import requests 
from threading import Timer 
import time 

LAST_REQUEST_MS = 0 
@app.before_request 
def update_last_request_ms(): 
    global LAST_REQUEST_MS 
    LAST_REQUEST_MS = time.time() * 1000 


@app.route('/seriouslykill', methods=['POST']) 
def seriouslykill(): 
    func = request.environ.get('werkzeug.server.shutdown') 
    if func is None: 
     raise RuntimeError('Not running with the Werkzeug Server') 
    func() 
    return "Shutting down..." 


@app.route('/kill', methods=['POST']) 
def kill(): 
    last_ms = LAST_REQUEST_MS 
    def shutdown(): 
     if LAST_REQUEST_MS <= last_ms: # subsequent requests abort shutdown 
      requests.post('http://localhost:5000/seriouslykill') 
     else: 
      pass 

    Timer(1.0, shutdown).start() # wait 1 second 
    return "Shutting down..." 
+0

to działa, ale czuje .. ._very_ hacky. Wiem, że minęło trochę czasu, ale czy kiedykolwiek znalazłeś czysty sposób na zrobienie tego, bez wysyłania prośby do siebie? – Juicy

2

Moja metoda może być przebiegała za pośrednictwem terminali bash/konsoli

1) uruchomić i uzyskać liczba proces

$ ps aux | grep yourAppKeywords 

2a) zabić proces

$ kill processNum 

2b) zabić proces, jeśli powyżej nie działa

$ kill -9 processNum 
+0

Jestem niemal pewien, że pytanie nie brzmi "jak zabić proces", a problem polega na tym, że wykonanie ctrl + c go nie zabija. Przy okazji używam 'kill -9 \' lsof -i: 5000-t \ '', ponieważ tylko 1 aplikacja może korzystać z portu i jest łatwa. – erm3nda

2

To stara sprawa, ale googling nie dał mi żadnego wglądu w jaki sposób tego dokonać.

Ponieważ nie przeczytałem poprawnie code here! (Doh!) Co robi jest podnieść RuntimeError gdy nie ma werkzeug.server.shutdown w request.environ ...

Więc co możemy zrobić, gdy nie ma request jest podnieść RuntimeError

def shutdown(): 
    raise RuntimeError("Server going down") 

i złap, że gdy app.run() powraca:

... 
try: 
    app.run(host="0.0.0.0") 
except RuntimeError, msg: 
    if str(msg) == "Server going down": 
     pass # or whatever you want to do when the server goes down 
    else: 
     # appropriate handling/logging of other runtime errors 
# and so on 
... 

Nie musisz wysyłać samemu żądania.

7

zrobiłem to nieco inne wykorzystujące wątki

from werkzeug.serving import make_server 

class ServerThread(threading.Thread): 

    def __init__(self, app): 
     threading.Thread.__init__(self) 
     self.srv = make_server('127.0.0.1', 5000, app) 
     self.ctx = app.app_context() 
     self.ctx.push() 

    def run(self): 
     log.info('starting server') 
     self.srv.serve_forever() 

    def shutdown(self): 
     self.srv.shutdown() 

def start_server(): 
    global server 
    app = flask.Flask('myapp') 
    ... 
    server = ServerThread(app) 
    server.start() 
    log.info('server started') 

def stop_server(): 
    global server 
    server.shutdown() 

Używam go do końca do końca zrobić testy na spokojny API, gdzie mogę wysyłać żądania za pomocą biblioteki wnioski Pythona.

+0

Nie udało mi się uzyskać innych rzeczy do roboty, ale to rozwiązanie działa świetnie! Dzięki za tonę! Dla innych osób: działa również z flakonikami spokojnymi! –

+0

To wydaje się blokować w oknach, dopóki nie uderzę go z inną prośbą ... w jakiś sposób? – Claudiu

+0

Mam ten sam problem co @Claudiu, z wyjątkiem Linuksa z pythonem 3.6.2 – micahscopes

Powiązane problemy