Cómo detener la aplicación del matraz sin usar ctrl-c


104

Quiero implementar un comando que pueda detener la aplicación de flask usando flask-script. He buscado la solución por un tiempo. Debido a que el marco no proporciona la API "app.stop ()", tengo curiosidad sobre cómo codificar esto. Estoy trabajando en Ubuntu 12.10 y Python 2.7.3.


¿Por qué necesita poder detener su aplicación desde un script? (La mejor herramienta para el trabajo dependerá de lo que intente hacer).
Sean Vieira

En serio, ¿qué intentas hacer aquí? Si está hablando de devserver para desarrollo, está perfectamente bien detenerlo así. En producción, no se implementa de esta manera y puede detener una solicitud en cualquier momento que desee, por lo que la "aplicación deja de ejecutarse".
Ignas Butėnas

@SeanVieira Quiero saber si hay alguna solución para hacer esto.
vic

@IgnasB. Estoy desarrollando un servicio RESTful en mi máquina en este momento. Estoy trabajando en un proyecto, tal vez me ayude a elegir qué máquinas debo implementar. La única forma en que puedo averiguarlo es apagar el proceso.
vic

3
@vrootic, pero no usará app.run () en producción de todos modos. app.run () se usa solo para el desarrollo y para probar su aplicación mientras se desarrolla. Hay diferentes formas de ejecutar Flask en producción, se pueden encontrar más aquí, por ejemplo, flask.pocoo.org/docs/quickstart/#deploying-to-a-web-server Y si ya implementa de alguna manera así (así que entendí mal pregunta), la forma de dejar de atender la solicitud que llega a Flask es detener el servidor http que la está sirviendo.
Ignas Butėnas

Respuestas:


125

Si solo está ejecutando el servidor en su escritorio, puede exponer un punto final para matar el servidor (lea más en 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...'

Aquí hay otro enfoque que está más contenido:

from multiprocessing import Process

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

Déjeme saber si esto ayuda.


16
¿Sabe si hay alguna forma de obtener la propiedad 'werkzeug.server.shutdown' sin necesidad de un contexto de solicitud?
Akatkinson

5
Tuve que cambiar el método de ruta a 'GET' para que funcionara.
CS

5
Para completar, a esta respuesta le falta la función que llamaría fuera de un contexto de solicitud para hacer el apagado, que no sería más que una solicitud HTTP al servidor (que puede originarse desde / hacia localhost)
JamesHutchison

1
Con methods='POST', obtengo un 405 Method not allowederror, mientras que con métodos = 'GET'`, funciona como sugirió @CS.
Agile Bean

1
No funcionó para mí en AWS Elastic Beanstalk.
Funcionó

34

Lo hice ligeramente diferente usando hilos.

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 para hacer pruebas de extremo a extremo para una api tranquila, donde puedo enviar solicitudes utilizando la biblioteca de solicitudes de Python.


2
No logré que las otras cosas funcionen, ¡pero esta solución funciona muy bien! ¡Gracias una tonelada! Para el resto de personas: ¡también funciona con frasco restful!
Jorrick Sleijster

Esto parece bloquearse en Windows hasta que lo golpeo con otra solicitud ... ¿alguna forma de evitar eso?
Claudiu

Tengo el mismo problema que @Claudiu, excepto en Linux con python 3.6.2
micahscopes

No sé por qué no se acepta, pero parece ser el más limpio y funciona muy bien sin dependencias adicionales. Muchas gracias.
Eric Reed

17

Este es un hilo un poco antiguo, pero si alguien que está experimentando, aprendiendo o probando una aplicación de matraz básico, comenzó desde un script que se ejecuta en segundo plano, la forma más rápida de detenerlo es matar el proceso que se ejecuta en el puerto en el que está ejecutando su aplicación. en. Nota: Soy consciente de que el autor está buscando una forma de no matar o detener la aplicación. Pero esto puede ayudar a alguien que está aprendiendo.

sudo netstat -tulnp | grep :5001

Obtendrá algo como esto.

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

Para detener la aplicación, finalice el proceso

sudo kill 28834

15

Mi método se puede realizar a través de la terminal / consola de bash

1) ejecutar y obtener el número de proceso

$ ps aux | grep yourAppKeywords

2a) mata el proceso

$ kill processNum

2b) mata el proceso si lo anterior no funciona

$ kill -9 processNum

9
Estoy casi seguro de que la pregunta no es "cómo matar un proceso", y el problema es que hacer ctrl + c no lo mata. Por cierto, uso kill -9 `lsof -i:5000 -t`porque solo una aplicación puede usar el puerto y es fácil.
m3nda

9

Como han señalado otros, solo puede usar werkzeug.server.shutdowndesde un controlador de solicitudes. La única forma que encontré para apagar el servidor en otro momento es enviarte una solicitud a ti mismo. Por ejemplo, el /killcontrolador en este fragmento matará al servidor de desarrollo a menos que entre otra solicitud durante el siguiente segundo:

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
esto funciona pero se siente ... muy hacky. Sé que ha pasado un tiempo, pero ¿alguna vez encontraste una manera limpia de hacer esto, sin enviarte una solicitud a ti mismo?
Jugoso

7

Esta es una vieja pregunta, pero buscar en Google no me dio ninguna idea de cómo lograrlo.

¡Porque no leí el código aquí correctamente! (¡Doh!) Lo que hace es levantar un RuntimeErrorcuando no hay werkzeug.server.shutdownen el request.environ...

Entonces, ¿qué podemos hacer cuando no hay requestes plantear unaRuntimeError

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

y coger eso cuando app.run()regrese:

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

No es necesario que se envíe una solicitud.


4

No tiene que presionar "CTRL-C", pero puede proporcionar un punto final que lo haga por usted:

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

Ahora puede llamar a este punto final para apagar correctamente el servidor:

curl localhost:5000/stopServer

Probé su código, pero después os.kill, el cliente no puede recibir la respuesta devuelta. Para curl, genera "curl: (56) Recv failure: Connection was reset". Puede ver también Ejecutar una función después de que Flask devuelva una respuesta para resolverlo.
samm

@samm, la conclusión de esa pregunta es que no es posible a menos que inicies un hilo diferente, ¿verdad? Entonces, ¿cómo se apaga el servidor de matraces desde ese hilo diferente?
Jurgy

3

Puedes usar el método a continuación

app.do_teardown_appcontext()

2

Si está trabajando en la CLI y solo tiene una aplicación / proceso de matraz en ejecución (o más bien, solo desea eliminar cualquier proceso de matraz que se esté ejecutando en su sistema), puede eliminarlo con:

kill $(pgrep -f flask)


1

Si está fuera del manejo de solicitudes y respuestas, aún puede:

import os
import signal

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

0

Instancia de VM de Google Cloud + Aplicación Flask

He alojado mi aplicación Flask en la máquina virtual de Google Cloud Platform. Inicié la aplicación usando python main.pyPero el problema era que ctrl + c no funcionaba para detener el servidor.

Este comando $ sudo netstat -tulnp | grep :5000termina el servidor.

La aplicación My Flask se ejecuta en el puerto 5000 de forma predeterminada.

Nota: Mi instancia de VM se ejecuta en Linux 9.

Funciona para esto. No he probado para otras plataformas. No dude en actualizar o comentar si también funciona para otras versiones.


-1

Para Windows, es bastante fácil detener / matar el servidor de flask -

  1. Ir al administrador de tareas
  2. Encuentra flask.exe
  3. Seleccionar y finalizar proceso

10
El botón de encendido de su computadora también es bastante efectivo jaja
Michael Green
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.