如何在不使用ctrl-c的情况下停止烧瓶应用


102

我想实现一个可以使用flask-script停止flask应用程序的命令。我已经搜索了一段时间。因为该框架不提供“ app.stop()” API,所以我对如何编写此代码感到好奇。我正在使用Ubuntu 12.10和Python 2.7.3。


为什么需要能够从脚本停止应用程序?(工作的最佳工具将取决于您要执行的操作)。
肖恩·维埃拉

说真的,您要在这里做什么?如果您谈论的是devserver进行开发,那么就最好停止它。在生产环境中,您不会像这样部署,并且您可以随时停止请求,因此“应用程序停止运行”。
IgnasButėnas2013年

@SeanVieira我想知道是否有解决方案可以做到这一点。
vic

@IgnasB。我现在正在机器上开发RESTful服务。我正在研究一个项目,也许它将帮助我选择应该部署的计算机。我唯一能弄清的方法是通过杀死进程来关闭计算机。
vic

3
@vrootic,但无论如何您都不会在生产中使用app.run()。app.run()仅用于开发并在开发时测试您的应用程序。在生产环境中运行Flask的方式有多种,在这里可以找到更多的示例,例如flask.pocoo.org/docs/quickstart/#deploying-to-a-web-server如果您已经以这种方式进行了部署(那么我就会误解了问题),停止向Flask发送请求的方法是停止正在为其提供服务的http服务器。
IgnasButėnas13年

Answers:


121

如果只是在桌面上运行服务器,则可以公开终结点以终止服务器(有关更多信息,请参见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...'

这是另一种包含更多的方法:

from multiprocessing import Process

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

让我知道是否有帮助。


15
您是否知道无需请求上下文即可获取“ werkzeug.server.shutdown”属性的任何方法?
2014年

5
我必须将路由方法更改为“ GET”才能正常工作。
CS CS

5
为了完整起见,此答案缺少您将在请求上下文外部调用以执行关闭功能的功能,该功能仅是对服务器的HTTP请求(可以源自/到本地主机)
JamesHutchison

1
使用时methods='POST',我得到一个405 Method not allowed错误,而使用methods ='GET'`时,它的工作方式就像@CS建议的那样。
敏捷豆

1
在AWS Elastic Beanstalk上对我不起作用。在本地
运作

34

我使用线程做了一点不同

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

我用它来进行静态API的端到端测试,在这里我可以使用python请求库发送请求。


2
我没有设法使其他东西起作用,但是该解决方案效果很好!万分感谢!对于其他人:它也可以在烧瓶静止时起作用!
Jorrick Sleijster '17

这似乎在Windows上阻塞,直到我用另一个请求击中它为止。
Claudiu

我遇到的问题与@Claudiu相同,但在Linux上使用python 3.6.2的情况除外
micahscopes

我不知道为什么不接受它,但是它似乎是最干净的,并且在没有任何额外依赖的情况下也能很好地工作。非常感谢。
埃里克·里德

17

这是一个有点旧的线程,但是如果有人从后台运行的脚本开始尝试,学习或测试基本的flask应用,则停止它的最快方法是终止正在运行您的应用的端口上运行的进程上。注意:我知道作者正在寻找一种不杀死或停止该应用程序的方式。但这可能会对正在学习的人有所帮助。

sudo netstat -tulnp | grep :5001

你会得到这样的东西。

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

要停止应用,请终止进程

sudo kill 28834

14

我的方法可以通过bash终端/控制台进行

1)运行并获取进程号

$ ps aux | grep yourAppKeywords

2a)终止进程

$ kill processNum

2b)如果以上方法无效,则终止该进程

$ kill -9 processNum

9
我几乎可以肯定,问题不在于“如何杀死进程”,而问题是执行ctrl + c不会杀死它。顺便说一句,我确实使用kill -9 `lsof -i:5000 -t`cuz,只有1个应用程序可以使用该端口,而且很容易。
m3nda

9

正如其他人指出的那样,您只能werkzeug.server.shutdown在请求处理程序中使用。我发现在另一时间关闭服务器的唯一方法是向自己发送请求。例如,/kill此片段中的处理程序将杀死开发服务器,除非在下一秒内收到另一个请求:

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
这可行,但感觉... hacky。我知道已经有一段时间了,但是您是否找到了一种干净的方法来执行此操作,而没有向自己发送请求?
多汁

7

这是一个古老的问题,但是谷歌搜索并没有给我任何有关如何完成此操作的见识。

因为我在这里没有正确阅读代码!(Do!)它的作用是在……中RuntimeError不存在时引发一个。werkzeug.server.shutdownrequest.environ

因此,如果没有,我们可以做的request就是提高RuntimeError

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

并在app.run()返回时捕捉到:

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

无需向自己发送请求。


4

您不必按“ CTRL-C”,但是您可以提供一个可以为您执行此操作的端点:

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

现在,您只需调用此端点即可正常关​​闭服务器:

curl localhost:5000/stopServer

我测试了您的代码,但之后os.kill,客户端无法接收到返回的响应。对于curl,它输出“卷曲:(56)接收失败:连接已重置”。在Flask返回响应以解决它后,可能还会看到执行一个函数
samm

@samm,这个问题的结论是,除非您启动其他线程,否则是不可能的,对吗?然后,如何从另一个线程关闭flask服务器?
Jurgy,


2

如果您使用的是CLI,并且仅运行一个Flask应用程序/进程(或者,您只想终止系统上运行的任何 flask进程),则可以使用以下命令将其终止:

kill $(pgrep -f flask)


1

如果您不在请求响应处理之外,则仍然可以:

import os
import signal

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

1

Google Cloud VM实例+ Flask应用

我将Flask应用程序托管在Google Cloud Platform虚拟机上。我使用来启动应用程序,python main.py但是问题是ctrl + c无法停止服务器。

此命令$ sudo netstat -tulnp | grep :5000终止服务器。

默认情况下,我的Flask应用程序在端口5000上运行。

注意:我的VM实例正在Linux 9上运行。

为此。尚未针对其他平台进行测试。如果它也适用于其他版本,请随时进行更新或评论。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.