ฉันต้องการใช้คำสั่งที่สามารถหยุดแอปพลิเคชัน flask โดยใช้ flask-script ฉันได้ค้นหาวิธีแก้ปัญหามาระยะหนึ่งแล้ว เนื่องจากเฟรมเวิร์กไม่มี API "app.stop ()" ฉันจึงอยากรู้เกี่ยวกับวิธีการเขียนโค้ด ฉันกำลังทำงานบน Ubuntu 12.10 และ Python 2.7.3
ฉันต้องการใช้คำสั่งที่สามารถหยุดแอปพลิเคชัน flask โดยใช้ flask-script ฉันได้ค้นหาวิธีแก้ปัญหามาระยะหนึ่งแล้ว เนื่องจากเฟรมเวิร์กไม่มี API "app.stop ()" ฉันจึงอยากรู้เกี่ยวกับวิธีการเขียนโค้ด ฉันกำลังทำงานบน 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.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()
โปรดแจ้งให้เราทราบหากสิ่งนี้ช่วยได้
methods='POST'
ฉันได้รับ405 Method not allowed
ข้อผิดพลาดในขณะที่วิธีการ = 'รับ' มันทำงานตามที่ @CS แนะนำ
ฉันทำมันแตกต่างกันเล็กน้อยโดยใช้เธรด
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()
ฉันใช้มันเพื่อทำการทดสอบ end to end สำหรับ 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
sudo kill -9 28834
ก่อนที่กระบวนการจะถูกฆ่า
วิธีการของฉันสามารถดำเนินการผ่าน bash terminal / console
1) เรียกใช้และรับหมายเลขกระบวนการ
$ ps aux | grep yourAppKeywords
2a) ฆ่ากระบวนการ
$ kill processNum
2b) ฆ่ากระบวนการหากด้านบนไม่ทำงาน
$ kill -9 processNum
kill -9 `lsof -i:5000 -t`
cuz ไม่เพียงแค่ 1 แอพเท่านั้นที่สามารถใช้พอร์ตได้และเป็นเรื่องง่าย
ตามที่คนอื่น ๆ ชี้ให้เห็นคุณสามารถใช้ได้werkzeug.server.shutdown
จากตัวจัดการคำขอเท่านั้น วิธีเดียวที่ฉันพบในการปิดเซิร์ฟเวอร์ในเวลาอื่นคือการส่งคำขอถึงตัวคุณเอง ตัวอย่างเช่น/kill
ตัวจัดการในข้อมูลโค้ดนี้จะฆ่าเซิร์ฟเวอร์ dev เว้นแต่จะมีคำขออื่นเข้ามาในช่วงวินาทีถัดไป:
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..."
นี่เป็นคำถามเก่า แต่ googling ไม่ได้ให้ข้อมูลเชิงลึกเกี่ยวกับวิธีการทำสิ่งนี้ให้สำเร็จ
เพราะฉันอ่านโค้ดที่นี่ไม่ถูก! (Doh!) มันทำอะไรได้บ้าง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
...
ไม่ต้องส่งคำร้องเอง
คุณไม่จำเป็นต้องกด "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
มันแสดงผล "curl: (56) Recv ล้มเหลว: การเชื่อมต่อถูกรีเซ็ต" อาจเห็นเรียกใช้ฟังก์ชันหลังจากที่ Flask ส่งกลับการตอบสนองเพื่อแก้ปัญหา
คุณสามารถใช้วิธีการร้อง
app.do_teardown_appcontext()
หากคุณกำลังทำงานบน CLI และมีเพียงหนึ่งแอปขวด / ขั้นตอนการทำงาน (หรือมากกว่าคุณต้องการเพียงแค่ต้องการที่จะฆ่าใด ๆกระบวนการขวดที่ทำงานบนระบบของคุณ) คุณสามารถฆ่ามันด้วย:
kill $(pgrep -f flask)
หากคุณอยู่นอกการจัดการคำขอตอบกลับคุณยังสามารถ:
import os
import signal
sig = getattr(signal, "SIGKILL", signal.SIGTERM)
os.kill(os.getpid(), sig)
หากมีคนอื่นกำลังมองหาวิธีหยุดเซิร์ฟเวอร์ Flask ภายในบริการ win32 - นี่คือ เป็นการผสมผสานที่แปลกประหลาดของหลาย ๆ วิธี แต่ก็ใช้ได้ดี แนวคิดหลัก:
shutdown
จุดสิ้นสุดที่สามารถใช้สำหรับการปิดเครื่องอย่างสง่างาม หมายเหตุ : ขึ้นอยู่กับrequest.environ.get
สิ่งที่ใช้งานได้เฉพาะในบริบทของคำขอเว็บเท่านั้น ( @app.route
ฟังก์ชันภายใน)SvcStop
วิธีการของ win32service ใช้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)
myservice.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://localhost:5001/shutdown')
ฉันโฮสต์แอปพลิเคชัน Flask บน Google Cloud Platform Virtual Machine ฉันเริ่มใช้แอพโดยใช้python main.py
แต่ปัญหาคือ ctrl + c ไม่ทำงานเพื่อหยุดเซิร์ฟเวอร์
คำสั่งนี้$ sudo netstat -tulnp | grep :5000
ยุติเซิร์ฟเวอร์
แอป My Flask ทำงานบนพอร์ต 5000 ตามค่าเริ่มต้น
มันใช้ได้กับสิ่งนี้ ยังไม่ได้ทดสอบสำหรับแพลตฟอร์มอื่น อย่าลังเลที่จะอัปเดตหรือแสดงความคิดเห็นหากใช้งานได้กับเวอร์ชันอื่นด้วย
ทำงานด้วย: 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'\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')
หากคุณประสบปัญหากับไอคอน Fav / การเปลี่ยนแปลงในการโหลด index.html (เช่นเวอร์ชันเก่าจะถูกแคชไว้) ให้ลอง "ล้างข้อมูลการท่องเว็บ> รูปภาพและไฟล์" ใน Chromeด้วย
ทำทุกอย่างข้างต้นและฉันได้รับไอคอน Fav ในที่สุดก็โหลดเมื่อเรียกใช้แอพ Flask
สำหรับ Windows มันค่อนข้างง่ายที่จะหยุด / ฆ่าเซิร์ฟเวอร์ขวด -