Как остановить колбу без использования Ctrl-C
Я хочу реализовать команду, которая может остановить приложение фляги с помощью flashk-скрипта. Я искал решение некоторое время. Поскольку платформа не предоставляет API "app.stop()", мне интересно, как это кодировать. Я работаю над Ubuntu 12.10 и Python 2.7.3.
21 ответ
Если вы просто запускаете сервер на своем рабочем столе, вы можете предоставить конечную точку для уничтожения сервера (подробнее см. " Завершение работы простого сервера"):
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()
Позвольте мне знать, если это помогает.
Я сделал это немного по-другому, используя темы
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.
Это немного старая тема, но если кто-то экспериментирует, изучает или тестирует базовое приложение фляги, запускается из скрипта, который работает в фоновом режиме, самый быстрый способ остановить это - убить процесс, запущенный на порте, на котором вы запускаете ваше приложение. на. Примечание. Мне известно, что автор ищет способ не убивать и не останавливать приложение. Но это может помочь тому, кто учится.
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
2а) убить процесс
$ kill processNum
2b) убить процесс, если выше не работает
$ kill -9 processNum
Вам не нужно нажимать "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
Как уже отмечали другие, вы можете использовать только werkzeug.server.shutdown
из обработчика запросов. Единственный способ, которым я нашел, чтобы выключить сервер в другое время, - это отправить запрос самому себе. Например, /kill
Обработчик в этом фрагменте убьет сервер dev, если в течение следующей секунды не поступит другой запрос:
import requests
from threading import Timer
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..."
Это старый вопрос, но поиск в Google не дал мне никакого представления о том, как этого добиться.
Потому что я не прочитал код здесь правильно! (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
...
Не нужно отправлять себе запрос.
Если вы работаете с CLI и у вас работает только одно приложение / процесс фляги (или, скорее, вы просто хотите убить любой процесс фляги, запущенный в вашей системе), вы можете убить его с помощью:
kill $(pgrep -f flask)
Если вы находитесь за пределами обработки запроса-ответа, вы все равно можете:
import os
import signal
sig = getattr(signal, "SIGKILL", signal.SIGTERM)
os.kill(os.getpid(), sig)
request.environ.get
устарело . Решение Павла Минаева довольно ясное:
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 внутри службы win32 - вот он. Это довольно странное сочетание нескольких подходов, но оно хорошо работает. Ключевые идеи:
- Это
shutdown
конечная точка, которую можно использовать для постепенного завершения работы. Примечание: он полагается наrequest.environ.get
который можно использовать только в контексте веб-запроса (внутри@app.route
-ed функция) - win32service's
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)
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')
Я обнаружил, что удаление собственного 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 SIGQUIT (15) instead.
app.run(host='0.0.0.0', port=8000)
Я тестировал это на Ubuntu 22.04 LTS и на Window$ 10. Это работает на обоих.
Чтобы вызвать уничтожение сервера, просто запроситеhttp://127.0.0.1/kill-backend
и это потерпит неудачу сconnection refused
ошибка, потому что сервер сразу мертв.
Если порт известен (например, 5000), я нашел простое решение: введите:
fuser -k 5000/tcp
это убьет процесс на порту 5000.
Как убить процесс, работающий на определенном порту в Linux?
Решение 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'\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.
Выполнив все вышеперечисленное, я получил свой значок, который наконец загрузился после запуска моего приложения Flask.
Экземпляр виртуальной машины Google Cloud + приложение Flask
Я разместил свое приложение Flask на виртуальной машине Google Cloud Platform. Я запустил приложение, используяpython main.py
Но проблема была в том, что ctrl+c не помогло остановить сервер.
Эта команда $ sudo netstat -tulnp | grep :5000
завершает работу сервера.
Приложение My Flask по умолчанию работает на порту 5000.
Примечание. Мой экземпляр виртуальной машины работает в Linux 9.
Это работает для этого. На других платформах не тестировался. Не стесняйтесь обновлять или комментировать, если это работает и для других версий.
вы можете попробовать использовать
pkill python
pkill — это утилита командной строки, которая отправляет сигналы процессам работающей программы на основе заданных критериев. Процессы могут быть указаны по их полным или частичным именам, по пользователю, запускающему процесс, или по другим атрибутам.
Команда pkill является частью пакета procps (или procps-ng), который предварительно установлен почти во всех дистрибутивах Linux. pkill — это, по сути, оболочка программы pgrep, которая печатает только список соответствующих процессов. Как использовать команду pkill
Синтаксис команды pkill следующий:
pkill [OPTIONS] <PATTERN>
Соответствие задается с помощью расширенных регулярных выражений.
При вызове без каких-либо опций pkill отправляет сигнал 15 (TERM) PID всех запущенных программ, соответствующих данному имени. Например, чтобы корректно остановить все процессы Firefox, вы должны запустить:
pkill -15 python
Команда возвращает 0, если хотя бы один запущенный процесс соответствует запрошенному имени. В противном случае код выхода равен 1. Это может быть полезно при написании сценариев оболочки.
больше информации здесь
Проблема в том, что werkzeugBaseWSGIServer
экземпляр, созданный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 в потоке и не беспокоиться о том, что он останется работоспособным, пока я выполняю другие тесты.
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 довольно легко остановить / убить флеш-сервер -
- Перейти к диспетчеру задач
- Найдите flask.exe
- Выбрать и завершить процесс