151

我想实现一个可以通过使用烧瓶脚本停止烧瓶应用程序的命令。我已经搜索了一段时间的解决方案。因为该框架不提供app.stop()API,所以我很好奇如何编写代码。我正在开发 Ubuntu 12.10 和 Python 2.7.3。

4

16 回答 16

179

如果您只是在桌面上运行服务器,您可以公开一个端点来终止服务器(在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.get('/shutdown')
def shutdown():
    shutdown_server()
    return 'Server shutting down...'
    

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

from multiprocessing import Process

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

让我知道这是否有帮助。

于 2013-06-11T20:47:13.663 回答
58

我使用线程做的略有不同

from werkzeug.serving import make_server

class ServerThread(threading.Thread):

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

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

    def shutdown(self):
        self.server.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()

我用它来对restful api进行端到端测试,我可以使用python请求库发送请求。

于 2017-07-10T16:53:38.340 回答
26

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

sudo netstat -tulnp | grep :5001

你会得到这样的东西。

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

要停止应用程序,请终止该进程

sudo kill 28834
于 2018-07-23T01:54:38.377 回答
20

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

1)运行并获取进程号

$ ps aux | grep yourAppKeywords

2a) 终止进程

$ kill processNum

2b)如果以上不起作用,则终止该进程

$ kill -9 processNum
于 2016-08-19T06:57:29.413 回答
13

正如其他人指出的那样,您只能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.post('/seriouslykill')
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.post('/kill')
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..."
于 2014-11-06T19:59:15.707 回答
10

这是一个古老的问题,但谷歌搜索并没有让我了解如何实现这一点。

因为我没有正确阅读这里的代码!(Doh!)它的作用RuntimeErrorwerkzeug.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
...

无需向自己发送请求。

于 2017-03-09T15:52:31.577 回答
6

如果您正在使用 CLI 并且只有一个烧瓶应用程序/进程正在运行(或者更确切地说,您只想终止系统上运行的任何烧瓶进程),您可以使用以下命令终止它:

kill $(pgrep -f flask)

于 2020-01-15T16:26:51.657 回答
6

如果您不在请求-响应处理范围内,您仍然可以:

import os
import signal

sig = getattr(signal, "SIGKILL", signal.SIGTERM)
os.kill(os.getpid(), sig)
于 2020-06-11T10:47:32.160 回答
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
于 2020-02-06T09:54:27.547 回答
3

如果其他人正在寻找如何在win32 服务中停止 Flask 服务器- 就在这里。这是几种方法的奇怪组合,但效果很好。关键思想:

  1. 这些是shutdown可用于优雅关闭的端点。注意:它依赖于哪个request.environ.get在 Web 请求的上下文中可用(内部-ed 函数)@app.route
  2. win32service 的SvcStop方法用于requests对服务本身进行 HTTP 请求。

myservice_svc.py

import win32service
import win32serviceutil
import win32event
import servicemanager
import time
import traceback
import os

import myservice


class MyServiceSvc(win32serviceutil.ServiceFramework):
    _svc_name_ = "MyServiceSvc"                       # NET START/STOP the service by the following name
    _svc_display_name_ = "Display name"  # this text shows up as the service name in the SCM
    _svc_description_ = "Description" # this text shows up as the description in the SCM

    def __init__(self, args):
        os.chdir(os.path.dirname(myservice.__file__))
        win32serviceutil.ServiceFramework.__init__(self, args)

    def SvcDoRun(self):
        # ... some code skipped
        myservice.start()

    def SvcStop(self):
        """Called when we're being shut down"""
        myservice.stop()
        # tell the SCM we're shutting down
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                              servicemanager.PYS_SERVICE_STOPPED,
                              (self._svc_name_, ''))

if __name__ == '__main__':
    os.chdir(os.path.dirname(myservice.__file__))
    win32serviceutil.HandleCommandLine(MyServiceSvc)

我的服务.py

from flask import Flask, request, jsonify

# Workaround - otherwise doesn't work in windows service.
cli = sys.modules['flask.cli']
cli.show_server_banner = lambda *x: None

app = Flask('MyService')

# ... business logic endpoints are skipped.

@app.route("/shutdown", methods=['GET'])
def shutdown():
    shutdown_func = request.environ.get('werkzeug.server.shutdown')
    if shutdown_func is None:
        raise RuntimeError('Not running werkzeug')
    shutdown_func()
    return "Shutting down..."


def start():
    app.run(host='0.0.0.0', threaded=True, port=5001)


def stop():
    import requests
    resp = requests.get('http://0.0.0.0:5001/shutdown')
于 2020-09-23T08:27:14.577 回答
1

您可以使用下面的方法

app.do_teardown_appcontext()
于 2019-08-21T14:24:54.390 回答
1

request.environ.get 已弃用Pavel Minaev的解决方案非常清楚:

import os
from flask import Flask


app = Flask(__name__)
exiting = False

@app.route("/exit")
def exit_app():
    global exiting
    exiting = True
    return "Done"

@app.teardown_request
def teardown(exception):
    if exiting:
        os._exit(0)
于 2021-11-02T15:30:41.760 回答
0

谷歌云虚拟机实例 + Flask 应用

我在谷歌云平台虚拟机上托管了我的 Flask 应用程序。我使用启动应用程序python main.py但问题是 ctrl+c 无法停止服务器。

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

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

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

它适用于此。其他平台没有测试。如果它也适用于其他版本,请随时更新或评论。

于 2020-08-11T00:48:12.523 回答
0

一个 Python 解决方案

运行: python kill_server.py

这仅适用于Windows。通过 PID 和 netstat 收集的 taskkill 杀死服务器。

# kill_server.py

import os
import subprocess
import re

port = 5000
host = '127.0.0.1'
cmd_newlines = r'\r\n'

host_port = host + ':' + str(port)
pid_regex = re.compile(r'[0-9]+$')

netstat = subprocess.run(['netstat', '-n', '-a', '-o'], stdout=subprocess.PIPE)  
# Doesn't return correct PID info without precisely these flags
netstat = str(netstat)
lines = netstat.split(cmd_newlines)

for line in lines:
    if host_port in line:
        pid = pid_regex.findall(line)
        if pid:
            pid = pid[0]
            os.system('taskkill /F /PID ' + str(pid))
        
# And finally delete the .pyc cache
os.system('del /S *.pyc')

如果您在加载 favicon / 更改 index.html 时遇到问题(即缓存旧版本),那么也可以在 Chrome 中尝试“清除浏览数据 > 图像和文件”

完成上述所有操作后,我终于在运行 Flask 应用程序时加载了我的图标。

于 2020-11-04T20:15:51.643 回答
0
app = MyFlaskSubclass()

...

app.httpd = MyWSGIServerSubclass()

...
 
@app.route('/shutdown')
def app_shutdown():
    from threading import Timer
    t = Timer(5, app.httpd.shutdown)
    t.start()
    return "Server shut down"
于 2022-01-05T22:07:58.503 回答
-6

对于 Windows,停止/杀死烧瓶服务器非常容易 -

  1. 转到任务管理器
  2. 找到烧瓶.exe
  3. 选择并结束进程
于 2019-06-21T20:27:08.727 回答