Comment arrêter l'application flask sans utiliser ctrl-c


104

Je veux implémenter une commande qui peut arrêter l'application flask en utilisant flask-script. J'ai cherché la solution pendant un moment. Parce que le framework ne fournit pas l'API "app.stop ()", je suis curieux de savoir comment coder cela. Je travaille sur Ubuntu 12.10 et Python 2.7.3.


Pourquoi avez-vous besoin de pouvoir arrêter votre application à partir d'un script? (Le meilleur outil pour le travail dépendra de ce que vous essayez de faire).
Sean Vieira

Sérieusement, qu'est-ce que vous essayez de faire ici? Si vous parlez de devserver pour le développement, c'est parfaitement bien de l'arrêter comme ça. En production, vous ne déployez pas comme ça et vous pouvez arrêter une demande à tout moment, de sorte que "l'application s'arrête de fonctionner".
Ignas Butėnas

@SeanVieira Je veux savoir s'il existe des solutions pour ce faire.
vic

@IgnasB. Je développe actuellement un service RESTful sur ma machine. Je travaille sur un projet, peut-être que cela m'aidera à choisir les machines que je dois déployer. La seule façon de comprendre est d'arrêter en tuant le processus.
vic

3
@vrootic, mais vous n'utiliserez pas app.run () en production de toute façon. app.run () est utilisé uniquement pour le développement et pour tester votre application pendant le développement. Il existe différentes manières d'exécuter Flask en production, vous pouvez en trouver d'autres ici, par exemple flask.pocoo.org/docs/quickstart/#deploying-to-a-web-server Et si vous déployez déjà comme ça (donc j'ai mal compris question), la manière d'arrêter de servir une requête à Flask est d'arrêter le serveur http qui la sert.
Ignas Butėnas

Réponses:


125

Si vous exécutez simplement le serveur sur votre bureau, vous pouvez exposer un point de terminaison pour tuer le serveur (en savoir plus sur 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...'

Voici une autre approche plus contenue:

from multiprocessing import Process

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

Faites-moi savoir si cela vous aide.


16
Savez-vous s'il existe un moyen d'obtenir la propriété 'werkzeug.server.shutdown' sans avoir besoin d'un contexte de requête?
akatkinson

5
J'ai dû changer la méthode d'itinéraire en «GET» pour qu'elle fonctionne.
CS

5
Pour être complet, cette réponse ne contient pas la fonction que vous appelleriez en dehors d'un contexte de demande pour effectuer l'arrêt, qui ne serait rien de plus qu'une requête HTTP au serveur (qui peut provenir de / vers localhost)
JamesHutchison

1
Avec methods='POST', j'obtiens une 405 Method not allowederreur, alors qu'avec methods = 'GET'`, cela fonctionne comme @CS suggéré.
Agile Bean

1
Cela n'a pas fonctionné pour moi sur AWS Elastic Beanstalk. A bien fonctionné localement
Andrey Bulezyuk

34

Je l'ai fait légèrement différemment en utilisant des fils

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

Je l'utilise pour faire des tests de bout en bout pour une api reposante, où je peux envoyer des requêtes à l'aide de la bibliothèque de requêtes python.


2
Je n'ai pas réussi à faire fonctionner les autres trucs mais cette solution fonctionne très bien! Merci beaucoup! Pour les autres: ça marche aussi avec flacon reposant!
Jorrick Sleijster

Cela semble bloquer sur Windows jusqu'à ce que je le frappe avec une autre demande ... de quelque façon que ce soit?
Claudiu

J'ai le même problème que @Claudiu, sauf sous Linux avec python 3.6.2
micahscopes

Je ne sais pas pourquoi cela n'est pas accepté, mais cela semble être le plus propre et fonctionne très bien sans aucune dépendance supplémentaire. Merci beaucoup.
Eric Reed le

17

C'est un fil un peu ancien, mais si quelqu'un expérimente, apprend ou teste une application flask de base, a commencé à partir d'un script qui s'exécute en arrière-plan, le moyen le plus rapide de l'arrêter est de tuer le processus en cours d'exécution sur le port sur lequel vous exécutez votre application. sur. Remarque: je sais que l'auteur cherche un moyen de ne pas tuer ou d'arrêter l'application. Mais cela peut aider quelqu'un qui apprend.

sudo netstat -tulnp | grep :5001

Vous obtiendrez quelque chose comme ça.

tcp 0 0 0.0.0.0:5001 0.0.0.0:* ÉCOUTER 28834 / python

Pour arrêter l'application, arrêtez le processus

sudo kill 28834

15

Ma méthode peut être effectuée via le terminal / console bash

1) exécuter et obtenir le numéro de processus

$ ps aux | grep yourAppKeywords

2a) Tuez le processus

$ kill processNum

2b) Tuez le processus si ci-dessus ne fonctionne pas

$ kill -9 processNum

9
Je suis presque sûr que la question n'est pas "comment tuer un processus", et le problème est que faire ctrl + c ne le tue pas. Btw, j'utilise parce que kill -9 `lsof -i:5000 -t`rien d'autre qu'une seule application ne peut utiliser le port et c'est facile.
m3nda

9

Comme d'autres l'ont souligné, vous ne pouvez utiliser qu'à werkzeug.server.shutdownpartir d'un gestionnaire de requêtes. Le seul moyen que j'ai trouvé pour arrêter le serveur à un autre moment est de vous envoyer une demande. Par exemple, le /killgestionnaire de cet extrait de code tuera le serveur de développement à moins qu'une autre requête n'entre dans la seconde suivante:

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
cela fonctionne mais semble ... très piraté. Je sais que cela fait un moment, mais avez-vous déjà trouvé un moyen propre de le faire, sans vous envoyer de demande?
Juicy

7

C'est une vieille question, mais la recherche sur Google ne m'a pas permis de savoir comment y parvenir.

Parce que je n'ai pas lu correctement le code ici ! (Doh!) Ce qu'il fait, c'est élever un RuntimeErrorquand il n'y a pas werkzeug.server.shutdowndans le request.environ...

Donc, ce que nous pouvons faire quand il n'y a pas, requestc'est d'élever unRuntimeError

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

et attraper ça quand app.run()revient:

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

Pas besoin de vous envoyer une demande.


4

Vous n'êtes pas obligé d'appuyer sur "CTRL-C", mais vous pouvez fournir un point de terminaison qui le fait pour vous:

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..." })

Vous pouvez maintenant simplement appeler ce point de terminaison pour arrêter le serveur en douceur:

curl localhost:5000/stopServer

J'ai testé votre code, mais après os.kill, la réponse retournée ne peut pas être reçue par le client. Pour curl, il génère "curl: (56) Recv failure: Connection was reset". Voir aussi Exécuter une fonction après que Flask a renvoyé une réponse pour la résoudre.
samm le

@samm, la conclusion de cette question est que ce n'est pas possible à moins que vous ne commenciez un autre fil de discussion, non? Alors, comment arrêtez-vous le serveur Flask à partir de ce thread différent?
Jurgy

3

Vous pouvez utiliser la méthode ci-dessous

app.do_teardown_appcontext()

2

Si vous travaillez sur la CLI et n'avez qu'une seule application / processus flask en cours d'exécution (ou plutôt, vous voulez simplement tuer tout processus flask en cours d'exécution sur votre système), vous pouvez le tuer avec:

kill $(pgrep -f flask)


1

Si vous êtes en dehors du traitement des demandes-réponses, vous pouvez toujours:

import os
import signal

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

0

Instance de VM Google Cloud + application Flask

J'ai hébergé mon application Flask sur la machine virtuelle Google Cloud Platform. J'ai démarré l'application en utilisant python main.pyMais le problème était que ctrl + c ne fonctionnait pas pour arrêter le serveur.

Cette commande $ sudo netstat -tulnp | grep :5000met fin au serveur.

L'application My Flask s'exécute sur le port 5000 par défaut.

Remarque: mon instance de VM s'exécute sous Linux 9.

Cela fonctionne pour cela. Je n'ai pas testé pour d'autres plates-formes. N'hésitez pas à mettre à jour ou à commenter si cela fonctionne également pour d'autres versions.


-1

Pour Windows, il est assez facile d'arrêter / de tuer le serveur flask -

  1. Aller au gestionnaire de tâches
  2. Trouvez flask.exe
  3. Sélectionner et terminer le processus

10
Le bouton d'alimentation de votre ordinateur est également très efficace haha
Michael Green
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.