Python 如何在不使用ctrl-c的情况下停止flask应用程序

Python 如何在不使用ctrl-c的情况下停止flask应用程序,python,flask,flask-extensions,Python,Flask,Flask Extensions,我想实现一个命令,它可以通过使用flask脚本来停止flask应用程序。 我已经寻找解决办法一段时间了。因为该框架不提供“app.stop()”API,所以我很好奇如何对其进行编码。我正在使用Ubuntu12.10和Python2.7.3。如果您只是在桌面上运行服务器,您可以公开一个端点来终止服务器(请参阅以下网址了解更多信息): 以下是另一种更具包容性的方法: from multiprocessing import Process server = Process(target=app.ru

我想实现一个命令,它可以通过使用flask脚本来停止flask应用程序。
我已经寻找解决办法一段时间了。因为该框架不提供“app.stop()”API,所以我很好奇如何对其进行编码。我正在使用Ubuntu12.10和Python2.7.3。

如果您只是在桌面上运行服务器,您可以公开一个端点来终止服务器(请参阅以下网址了解更多信息):

以下是另一种更具包容性的方法:

from multiprocessing import Process

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

请告诉我这是否有帮助。

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

导入请求
从线程导入计时器
从烧瓶进口请求
导入时间
上次请求\u MS=0
@请求前的应用程序
def update_last_request_ms():
全局最后请求\u MS
上次请求\u MS=time.time()*1000
@app.route('/seriouslykill',methods=['POST'])
def seriouslykill():
func=request.environ.get('werkzeug.server.shutdown')
如果func为无:
raise RUNTIMERROR('未与Werkzeug服务器一起运行')
func()
返回“正在关闭…”
@app.route('/kill',methods=['POST'])
def kill():
last_ms=last_REQUEST_ms
def shutdown():

如果上次请求,我的方法可以通过bash终端/控制台进行

1) 运行并获取进程号

$ ps aux | grep yourAppKeywords
2a)终止该过程

$ kill processNum
sudo kill 28834
2b)如果上述操作不起作用,则停止该过程

$ kill -9 processNum

这是一个老生常谈的问题,但谷歌没有给我任何关于如何做到这一点的见解

因为我没有正确地阅读这本书!(Doh!) 它所做的是在
请求.environ
中没有
werkzeug.server.shutdown
时引发
运行时错误

因此,当没有
请求时,我们可以做的是引发
运行时错误

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

无需向自己发送请求。

我使用的线程略有不同

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

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

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

sudo netstat -tulnp | grep :5001
你会得到这样的东西

tcp 0.0.0.0:5001 0.0.0.0:*听28834/python

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

$ kill processNum
sudo kill 28834

对于Windows,停止/终止flask服务器非常容易-

  • 转到任务管理器
  • 查找flask.exe
  • 选择并结束流程

  • 你可以使用下面的方法

    app.do_teardown_appcontext()
    

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

    kill$(pgrep-f flask)

    您不必按“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
    

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

    import os
    import signal
    
    sig = getattr(signal, "SIGKILL", signal.SIGTERM)
    os.kill(os.getpid(), sig)
    
    Google云虚拟机实例+Flask应用 我在谷歌云平台虚拟机上托管了我的Flask应用程序。 我使用
    python main.py
    启动应用程序,但问题是ctrl+c无法停止服务器

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

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

    注意:我的VM实例在Linux 9上运行。 这是有效的。没有测试过其他平台。
    如果它也适用于其他版本,请随时更新或发表评论。

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

  • 这是可用于正常关机的
    shutdown
    端点。注意:它依赖于
    request.environment.get
    ,它仅在web请求的上下文中可用(在
    @app.route
    -ed函数中)
  • Win32 service的
    SvcStop
    方法使用
    requests
    对服务本身执行HTTP请求
  • myservice\u 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)
    
    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://localhost:5001/shutdown')
    
    myservice.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)
    
    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://localhost:5001/shutdown')
    
    Python解决方案 运行时使用:
    python kill\u server.py

    这仅适用于Windows。使用taskkill、通过PID、通过netstat收集来杀死服务器

    # 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')
    
    如果您在加载index.html(即缓存旧版本)时遇到问题,请尝试在Chrome中“清除浏览数据>图像和文件”


    完成以上所有操作后,我的favicon终于可以在运行我的Flask应用程序时加载。

    为什么需要能够从脚本停止应用程序?(这项工作的最佳工具取决于你想做什么)。说真的,你想在这里做什么?如果您谈论的是devserver for development,那么完全可以这样停止它。在生产环境中,您不会这样部署,您可以随时停止请求,因此“应用程序停止运行”。@SeanVieira我想知道是否有任何解决方案可以做到这一点。@IgnasB。我现在正在我的机器上开发一个RESTful服务。我正在做一个项目,也许它可以帮助我选择应该部署哪些机器。我唯一能确定的方法是通过终止进程来关闭。@vrootic,但无论如何,您都不会在生产环境中使用app.run()。app.run()仅用于开发和测试应用程序,同时