Come interrompere l'applicazione Flask senza usare ctrl-c


102

Voglio implementare un comando che può arrestare l'applicazione flask utilizzando flask-script. Ho cercato la soluzione per un po '. Poiché il framework non fornisce l'API "app.stop ()", sono curioso di sapere come codificarlo. Sto lavorando su Ubuntu 12.10 e Python 2.7.3.


Perché devi essere in grado di interrompere la tua applicazione da uno script? (Lo strumento migliore per il lavoro dipenderà da ciò che stai cercando di fare).
Sean Vieira

Seriamente, cosa stai cercando di fare qui? Se stai parlando di devserver per lo sviluppo, va benissimo fermarlo in questo modo. In produzione non distribuisci in questo modo e puoi interrompere una richiesta in qualsiasi momento tu voglia, in modo che "l'app smetta di funzionare".
Ignas Butėnas

@SeanVieira Voglio sapere se ci sono soluzioni per farlo.
vic

@IgnasB. In questo momento sto sviluppando un servizio RESTful sulla mia macchina. Sto lavorando a un progetto, forse mi aiuterà a scegliere quali macchine dovrei distribuire. L'unico modo per capirlo è spegnerlo uccidendo il processo.
vic

3
@vrootic, ma non utilizzerai comunque app.run () in produzione. app.run () viene utilizzato solo per lo sviluppo e per testare l'applicazione durante lo sviluppo. Esistono diversi modi per eseguire Flask in produzione, altri possono essere trovati qui, ad esempio flask.pocoo.org/docs/quickstart/#deploying-to-a-web-server E se si distribuisce in qualche modo già (quindi ho frainteso domanda), il modo per interrompere il servizio di richieste in arrivo a Flask è arrestare il server http che lo sta servendo.
Ignas Butėnas

Risposte:


121

Se stai solo eseguendo il server sul desktop, puoi esporre un endpoint per uccidere il server (leggi di più su 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...'

Ecco un altro approccio più contenuto:

from multiprocessing import Process

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

Fammi sapere se questo aiuta.


15
Sai se c'è un modo per ottenere la proprietà 'werkzeug.server.shutdown' senza bisogno di un contesto di richiesta?
akatkinson

5
Ho dovuto cambiare il metodo del percorso in "GET" per farlo funzionare.
CS

5
Per completezza questa risposta manca la funzione che chiameresti al di fuori di un contesto di richiesta per eseguire lo shutdown, che non sarebbe altro che una richiesta HTTP al server (che può provenire da / a localhost)
JamesHutchison

1
Con methods='POST', ottengo un 405 Method not allowederrore, mentre con metodi = 'GET'`, funziona come suggerito da @CS.
Agile Bean

1
Non ha funzionato per me su AWS Elastic Beanstalk. Ha funzionato bene a livello locale
Andrey Bulezyuk

34

L'ho fatto in modo leggermente diverso usando i thread

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

Lo uso per eseguire test end to end per API riposanti, dove posso inviare richieste utilizzando la libreria di richieste python.


2
Non sono riuscito a far funzionare le altre cose ma questa soluzione funziona alla grande! Grazie mille! Per le altre persone: funziona anche con borraccia riposante!
Jorrick Sleijster

Questo sembra bloccarsi su Windows fino a quando non lo colpisco con un'altra richiesta ... in qualche modo aggirarlo?
Claudiu

Ho lo stesso problema di @Claudiu, tranne su Linux con python 3.6.2
micahscopes

Non so perché questo non sia accettato, ma sembra essere il più pulito e funziona alla grande senza dipendenze extra. Grazie mille.
Eric Reed

17

Questo è un thread un po 'vecchio, ma se qualcuno che sta sperimentando, imparando o testando l'app flask di base, ha iniziato da uno script che viene eseguito in background, il modo più rapido per fermarlo è terminare il processo in esecuzione sulla porta su cui si sta eseguendo l'app sopra. Nota: sono consapevole che l'autore sta cercando un modo per non uccidere o interrompere l'app. Ma questo può aiutare qualcuno che sta imparando.

sudo netstat -tulnp | grep :5001

Otterrai qualcosa di simile.

tcp 0 0 0.0.0.0:5001 0.0.0.0:* LISTEN 28834 / python

Per interrompere l'app, interrompi il processo

sudo kill 28834

14

Il mio metodo può essere eseguito tramite terminale / console bash

1) esegui e ottieni il numero del processo

$ ps aux | grep yourAppKeywords

2a) uccidi il processo

$ kill processNum

2b) uccidi il processo se sopra non funziona

$ kill -9 processNum

9
Sono quasi sicuro che la domanda non sia "come terminare un processo" e il problema è che fare ctrl + c non lo uccide. A proposito, io uso perché kill -9 `lsof -i:5000 -t`solo 1 app può usare la porta ed è facile.
m3nda

9

Come altri hanno sottolineato, puoi usare solo werkzeug.server.shutdownda un gestore di richieste. L'unico modo che ho trovato per chiudere il server in un altro momento è inviare una richiesta a te stesso. Ad esempio, il /killgestore in questo frammento ucciderà il server di sviluppo a meno che non arrivi un'altra richiesta durante il secondo successivo:

import requests
from threading import Timer
from flask import request
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..."

2
funziona ma sembra ... molto hacky. So che è passato del tempo, ma hai mai trovato un modo pulito per farlo, senza inviare una richiesta a te stesso?
Juicy

7

Questa è una vecchia domanda, ma googling non mi ha dato alcuna idea su come farlo.

Perché non ho letto correttamente il codice qui ! (Doh!) Quello che fa è sollevare a RuntimeErrorquando non c'è werkzeug.server.shutdownnel request.environ...

Quindi quello che possiamo fare quando non c'è requestè aumentare aRuntimeError

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

e prendilo quando app.run()ritorna:

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

Non c'è bisogno di inviarti una richiesta.


4

Non devi premere "CTRL-C", ma puoi fornire un endpoint che lo fa per te:

from flask import Flask, jsonify, request
import json, os, signal

@app.route('/stopServer', methods=['GET'])
def stopServer():
    os.kill(os.getpid(), signal.SIGINT)
    return jsonify({ "success": True, "message": "Server is shutting down..." })

Ora puoi semplicemente chiamare questo endpoint per arrestare correttamente il server:

curl localhost:5000/stopServer

Ho testato il tuo codice, ma dopo os.kill, la risposta restituita non può essere ricevuta dal cliente. Per curl, restituisce "curl: (56) Recv failure: Connection was reset". Può vedere anche Eseguire una funzione dopo che Flask ha restituito la risposta per risolverlo.
samm

@samm, la conclusione da questa domanda è che non è possibile a meno che non inizi un thread diverso, giusto? Allora come si fa a chiudere il server flask da quel thread diverso?
Jurgy

3

Puoi usare il metodo qui sotto

app.do_teardown_appcontext()

2

Se stai lavorando sulla CLI e hai solo un'app / processo flask in esecuzione (o meglio, vuoi semplicemente uccidere qualsiasi processo flask in esecuzione sul tuo sistema), puoi ucciderlo con:

kill $(pgrep -f flask)


1

Se sei al di fuori della gestione della richiesta-risposta, puoi comunque:

import os
import signal

sig = getattr(signal, "SIGKILL", signal.SIGTERM)
os.kill(os.getpid(), sig)

1

Istanza VM di Google Cloud + app Flask

Ho ospitato la mia applicazione Flask su Google Cloud Platform Virtual Machine. Ho avviato l'app utilizzando python main.pyMa il problema era che ctrl + c non funzionava per arrestare il server.

Questo comando $ sudo netstat -tulnp | grep :5000termina il server.

La mia app Flask viene eseguita sulla porta 5000 per impostazione predefinita.

Nota: la mia istanza VM è in esecuzione su Linux 9.

Funziona per questo. Non sono stati testati per altre piattaforme. Sentiti libero di aggiornare o commentare se funziona anche per altre versioni.


-1

Per Windows, è abbastanza facile arrestare / uccidere il server flask -

  1. Vai a Task Manager
  2. Trova flask.exe
  3. Seleziona e termina il processo

9
Anche il pulsante di accensione sul tuo computer è abbastanza efficace ahah
Michael Green
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.