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

2025-03-04 08:24:00
admin
原创
99
摘要:问题描述:我想使用 flask-script 实现一个可以停止 flask 应用程序的命令。我搜索了一段时间的解决方案。由于框架不提供app.stop()API,我很好奇如何编写代码。我正在使用 Ubuntu 12.10 和 Python 2.7.3。解决方案 1:如果您只是在桌面上运行服务器,则可以公开一个...

问题描述:

我想使用 flask-script 实现一个可以停止 flask 应用程序的命令。我搜索了一段时间的解决方案。由于框架不提供app.stop()API,我很好奇如何编写代码。我正在使用 Ubuntu 12.10 和 Python 2.7.3。


解决方案 1:

如果您只是在桌面上运行服务器,则可以公开一个端点来终止服务器(有关详细信息,请参阅关闭简单服务器):

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

如果这有帮助的话请告诉我。

解决方案 2:

我使用线程做了稍微不同的事

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')
    # App routes defined here
    server = ServerThread(app)
    server.start()
    log.info('server started')

def stop_server():
    global server
    server.shutdown()

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

解决方案 3:

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

sudo netstat -tulnp | grep :5001

你会得到类似这样的东西。

tcp 0 0 0.0.0.0:5001 0.0.0.0:* 监听 28834/python

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

sudo kill 28834

解决方案 4:

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

1)运行并获取进程号

$ ps aux | grep yourAppKeywords

2a)终止进程

$ kill processNum

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

$ kill -9 processNum

解决方案 5:

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

解决方案 6:

正如其他人指出的那样,您只能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..."

解决方案 7:

这是一个老问题,但谷歌搜索并没有给我任何有关如何实现这一目标的见解。

因为我没有仔细阅读这里的代码!(哎呀!)它所做的就是在RuntimeError没有时引发...werkzeug.server.shutdown`request.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
...

无需向自己发送请求。

解决方案 8:

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

kill $(pgrep -f flask)

解决方案 9:

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

import os
import signal

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

解决方案 10:

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)

解决方案 11:

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

  1. 这些是shutdown可用于正常关闭的端点。注意:它依赖于在 Web 请求上下文中request.environ.get可用(在-ed 函数内)@app.route

  2. win32service 的SvcStop方法用于requests对服务本身发出 HTTP 请求。

我的服务

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://0.0.0.0:5001/shutdown')

解决方案 12:

我发现杀死自己的PID似乎有效,如下所示:

import os
from flask import Flask

app = Flask(__name__)
own_pid = os.getpid() # Get the main process's PID in a global variable

@app.route('/kill-backend')
def kill_backend():
    global own_pid # Make sure to use the global variable
    os.kill(own_pid, 9) # The second argument is the signal, 9 stands for SIGKILL.
#If you want to "politely ask" the server to quit you can use SIGTERM (3) or SIGQUIT (15) instead.

app.run(host='0.0.0.0', port=8000)

我已经在 Ubuntu 22.04 LTS 和 Windows$ 10 上测试过它。它在两者上都可以运行。

要触发服务器终止,只需发出请求http://localhost:8000/kill-backend,它就会失败并出现connection refused错误,因为服务器立即终止。

解决方案 13:

如果已知端口(例如,5000),我发现一个简单的解决方案是输入:

fuser -k 5000/tcp

这将终止端口 5000 上的进程。

如何在 Linux 中终止在特定端口上运行的进程?

解决方案 14:

Python 解决方案

运行方式: python kill_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'
'

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 应用程序时加载了我的图标。

解决方案 15:

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"

解决方案 16:

您可以使用下面的方法

app.do_teardown_appcontext()

解决方案 17:

Google Cloud VM 实例 + Flask 应用

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

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

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

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

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

解决方案 18:

我的bash脚本变体(LINUX):

#!/bin/bash
portFind="$1"
echo "Finding process on port: $portFind"
pid=$(netstat -tulnp | grep :"$1" | awk '{print $7}' | cut -f1 -d"/")
echo "Process found: $pid"
kill -9 $pid
echo "Process $pid killed"

使用示例:

sudo bash killWebServer.sh 2223

输出:

Finding process on port: 2223
Process found: 12706
Process 12706 killed

解决方案 19:

问题在于,BaseWSGIServer由 创建的 werkzeug 实例werkzeug.serving.run_simple()(由 调用app.run())无法访问。然而,此类确实定义了一个干净的shutdown()方法,可以有效地终止服务器的主循环,而无需任何黑客攻击。

因此,如果我们可以访问该实例,我们就可以关闭服务器。我能想到的一种方法是使用垃圾收集器的对象跟踪:

@app.route("/shutdown", methods=["POST"])
def shutdown():
    for obj in gc.get_objects():
        try:
            if isinstance(obj, BaseWSGIServer):
                obj.shutdown()
                return "bye"
        except:
            pass
    return "failed"

我发现自己需要这个来模拟在我的单元测试中进行 POST 回调。使用这个函数,我可以在线程中运行 flask 服务器,而不用担心它在我运行其他测试时是否处于活动状态。

解决方案 20:

你可以尝试使用

pkill python

pkill 是一个命令行实用程序,它根据给定的标准向正在运行的程序的进程发送信号。可以通过进程的完整或部分名称、运行进程的用户或其他属性来指定进程。

pkill 命令是 procps(或 procps-ng)软件包的一部分,该软件包已预安装在几乎所有 Linux 发行版上。pkill 基本上是 pgrep 程序的包装器,它仅打印匹配进程的列表。如何使用 pkill 命令

pkill 命令的语法如下:

pkill [OPTIONS] <PATTERN>

使用扩展正则表达式来指定匹配。

当不带任何选项调用时,pkill 会向与给定名称匹配的所有正在运行的程序的 PID 发送 15(TERM)信号。例如,要正常停止所有 Firefox 进程,您可以运行:

pkill -15 python

当至少一个正在运行的进程与请求的名称匹配时,该命令将返回 0。否则,退出代码为 1。这在编写 shell 脚本时很有用。

更多信息请点击此处

Linux 中的 pkill 命令

解决方案 21:

对于 Windows,停止/杀死 flask 服务器相当容易 -

  1. 转到任务管理器

  2. 查找 flask.exe

  3. 选择并结束流程

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   3592  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   2442  
  敏捷每日站会作为敏捷项目管理中的关键环节,对于提升产品生命周期管理(PLM)效率有着不可忽视的作用。PLM涵盖了产品从概念产生到最终报废的全过程管理,涉及众多环节与人员,而每日站会能够通过优化沟通机制,让信息在团队中快速、准确地流动,从而推动整个PLM流程更加顺畅、高效。接下来,我们将深入探讨如何通过四步优化沟通机制,...
plm系统   17  
  在企业的发展进程中,产品生命周期管理(PLM)项目管理至关重要,而数据驱动决策则是提升PLM项目管理效能的关键手段。通过运用合适的分析模型,企业能够从海量数据中挖掘有价值的信息,为决策提供有力支撑,进而优化产品全生命周期的各个环节。以下将详细介绍助力PLM项目管理实现数据驱动决策的5大分析模型。需求分析模型需求分析是P...
plm系统功能介绍   19  
  PLM(产品生命周期管理)系统在企业的产品研发、生产与运营中扮演着至关重要的角色。它涵盖了从产品概念设计到退役的全流程管理,确保产品数据的有效整合与协同。然而,在复杂多变的商业环境中,黑天鹅事件随时可能降临,给企业带来难以预估的冲击。这些意外事件具有不可预测性、极大的影响力和事后的可解释性等特点,会对PLM系统的正常运...
plm系统的主要功能模块   16  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用