簡體   English   中英

如何在不使用 ctrl-c 的情況下停止燒瓶應用程序

[英]How to stop flask application without using ctrl-c

我想實現一個可以通過使用燒瓶腳本停止燒瓶應用程序的命令。 我已經搜索了一段時間的解決方案。 因為框架不提供app.stop() API,我很好奇如何編寫代碼。 我正在開發 Ubuntu 12.10 和 Python 2.7.3。

如果您只是在桌面上運行服務器,您可以公開一個端點來終止服務器(在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()

讓我知道這是否有幫助。

我使用線程做的略有不同

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請求庫發送請求。

這是一個有點老的線程,但是如果有人從后台運行的腳本開始試驗、學習或測試基本的燒瓶應用程序,停止它的最快方法是終止在您運行應用程序的端口上運行的進程上。 注意:我知道作者正在尋找一種不殺死或停止應用程序的方法。 但這可能對正在學習的人有所幫助。

sudo netstat -tulnp | grep :5001

你會得到這樣的東西。

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

要停止應用程序,請終止該進程

sudo kill 28834

我的方法可以通過 bash 終端/控制台進行

1)運行並獲取進程號

$ ps aux | grep yourAppKeywords

2a) 終止進程

$ kill processNum

2b)如果以上不起作用,則終止該進程

$ kill -9 processNum

正如其他人指出的那樣,您只能從請求處理程序中使用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..."

這是一個古老的問題,但谷歌搜索並沒有讓我了解如何實現這一點。

因為我沒有正確閱讀這里的代碼 (Doh!)它的作用是在request.environ中沒有werkzeug.server.shutdown時引發RuntimeError ...

所以當沒有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
...

無需向自己發送請求。

如果您正在使用 CLI 並且只有一個燒瓶應用程序/進程正在運行(或者更確切地說,您只想終止系統上運行的任何燒瓶進程),您可以使用以下命令終止它:

kill $(pgrep -f flask)

如果您不在請求-響應處理范圍內,您仍然可以:

import os
import signal

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

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

如果其他人正在尋找如何在win32 服務中停止 Flask 服務器 - 就在這里。 這是幾種方法的奇怪組合,但效果很好。 關鍵思想:

  1. 這些是shutdown端點,可用於正常關閉。 注意:它依賴於request.environ.get ,它只能在 Web 請求的上下文中使用(在@app.route -ed 函數內)
  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')

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)

您可以使用下面的方法

app.do_teardown_appcontext()

谷歌雲虛擬機實例 + Flask 應用

我在谷歌雲平台虛擬機上托管了我的 Flask 應用程序。 我使用python main.py啟動了應用程序,但問題是 ctrl+c 無法停止服務器。

這個命令$ sudo netstat -tulnp | grep :5000 $ sudo netstat -tulnp | grep :5000終止服務器。

默認情況下,我的 Flask 應用程序在端口 5000 上運行。

注意:我的 VM 實例在 Linux 9 上運行。

它適用於此。 其他平台沒有測試。 如果它也適用於其他版本,請隨時更新或評論。

一個 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 應用程序時加載了我的圖標。

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"

我的 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

對於 Windows,停止/殺死燒瓶服務器非常容易 -

  1. 轉到任務管理器
  2. 找到燒瓶.exe
  3. 選擇並結束進程

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM