Як зупинити застосування колби без використання ctrl-c


104

Я хочу реалізувати команду, яка може зупинити додаток flask за допомогою flask-script. Я шукав рішення деякий час. Оскільки фреймворк не надає API "app.stop ()", мені цікаво, як це кодувати. Я працюю над Ubuntu 12.10 та Python 2.7.3.


Чому вам потрібно мати можливість зупинити програму за допомогою сценарію? (Найкращий інструмент для роботи залежатиме від того, що ви намагаєтесь зробити).
Шон Віейра,

Серйозно, що ти тут намагаєшся робити? Якщо ви говорите про devserver для розробки, прекрасно зупинити його таким чином. На виробництві ви не розгортаєтесь таким чином, і ви можете зупинити запит у будь-який час, тому "додаток перестає працювати".
Ігнас Бутенас

@SeanVieira Я хочу знати, чи є якісь рішення для цього.
вік

@IgnasB. Зараз я розробляю послугу RESTful на своїй машині. Я працюю над проектом, можливо, це допоможе мені вибрати, які машини слід розгорнути. Єдиний спосіб, яким я можу зрозуміти, - це вимкнення шляхом вбивства процесу.
вік

3
@vrootic, але ви все одно не будете використовувати app.run () у виробництві. app.run () використовується лише для розробки та тестування вашого додатка під час розробки. Існують різні способи, як запустити Flask у виробництві, тут можна знайти більше, наприклад flask.pocoo.org/docs/quickstart/#deploying-to-a-web-server А якщо ви вже якось так розгортаєтесь (тому я неправильно зрозумів, питання), спосіб припинити подачу запиту, що надходить до Flask, - зупинити сервер http, який його обслуговує.
Ігнас Бутенас

Відповіді:


125

Якщо ви просто запускаєте сервер на робочому столі, ви можете виставити кінцеву точку для вбивства сервера (докладніше читайте на 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()

Повідомте мене, якщо це допоможе.


16
Чи знаєте ви, чи є спосіб отримати властивість 'werkzeug.server.shutdown' без необхідності контексту запиту?
akatkinson

5
Мені довелося змінити метод маршруту на 'GET', щоб змусити його працювати.
CS

5
Для повноти цієї відповіді відсутня функція, яку ви викликали б поза контекстом запиту, щоб зробити вимкнення, що було б не чим іншим, як HTTP-запитом до сервера (який може походити з / до localhost)
JamesHutchison,

1
З methods='POST', я отримую 405 Method not allowedпомилку, тоді як із методами = 'GET' ', це працює, як запропонував @CS.
Agile Bean

1
Не працював у мене на AWS Elastic Beanstalk.
Місцево

34

Я зробив це дещо інакше, використовуючи нитки

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

Я використовую його для виконання наскрізних тестів для спокійного API, де я можу надсилати запити за допомогою бібліотеки запитів python.


2
Мені не вдалося змусити інші речі працювати, але це рішення чудово працює! Дякую тонна! Для інших людей: це також працює зі спокійною колбою!
Jorrick Sleijster

Здається, це блокує вікна, доки я не натиснув його з іншим запитом ... як-небудь навколо цього?
Клавдіу,

У мене така ж проблема, як @Claudiu, за винятком Linux з python 3.6.2
micahscopes

Не знаю, чому це не прийнято, але, здається, це найчистіший і чудово працює без зайвих залежностей. Дуже дякую.
Ерік Рід

17

Це трохи стара тема, але якщо хтось експериментує, навчається або тестує базову програму-колбу, починаючи зі сценарію, який працює у фоновому режимі, найшвидший спосіб зупинити це - убити процес, що працює на порту, на якому запущена ваша програма на. Примітка. Я усвідомлюю, що автор шукає спосіб не вбити чи зупинити програму. Але це може допомогти тому, хто навчається.

sudo netstat -tulnp | grep :5001

Ви отримаєте щось подібне.

tcp 0 0 0.0.0.0:5001 0.0.0.0:* СЛУХАЙТЕ 28834 / python

Щоб зупинити програму, припиніть процес

sudo kill 28834

15

Мій метод можна продовжити через термінал / консоль bash

1) запустити і отримати номер процесу

$ ps aux | grep yourAppKeywords

2а) вбити процес

$ kill processNum

2b) вбити процес, якщо вище не працює

$ kill -9 processNum

9
Я майже впевнений, що питання полягає не в тому, "як вбити процес", і проблема полягає в тому, що використання ctrl + c не вбиває його. До речі, я використовую, тому що kill -9 `lsof -i:5000 -t`лише один додаток може використовувати порт, і це легко.
m3nda

9

Як зазначали інші, ви можете використовувати лише 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.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..."

2
це працює, але відчувається ... дуже хакі. Я знаю, що минув якийсь час, але чи знайшли ви коли-небудь чистий спосіб зробити це, не надіславши запит собі?
Соковитий

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

Не потрібно надсилати собі запит.


4

Вам не потрібно натискати "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 поверне відповідь для її вирішення.
самм

@samm, висновок з цього питання полягає в тому, що це неможливо, якщо ти не запустиш іншу тему, так? Тоді як вимкнути сервер колби з цього іншого потоку?
Юргій

3

Ви можете скористатися наведеним нижче способом

app.do_teardown_appcontext()

2

Якщо ви працюєте над CLI і у вас запущена лише одна програма / процес-колба (вірніше, ви просто хочете вбити будь-який процес колби, запущений у вашій системі), ви можете вбити:

kill $(pgrep -f flask)


1

Якщо ви знаходитесь поза обробкою запиту-відповіді, ви все ще можете:

import os
import signal

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

0

Екземпляр Google Cloud VM + додаток Flask

Я розмістив свою програму Flask на віртуальній машині Google Cloud Platform. Я запустив програму за допомогоюpython main.py але проблема в тому, що ctrl + c не спрацював, щоб зупинити сервер.

Ця команда $ sudo netstat -tulnp | grep :5000 припиняє роботу сервера.

Програма My Flask за замовчуванням працює на порту 5000.

Примітка: Мій екземпляр VM працює на Linux 9.

Це працює для цього. Не тестував для інших платформ. Не соромтеся оновлювати або коментувати, якщо це працює і для інших версій.


-1

Для Windows досить просто зупинити / убити сервер-колбу -

  1. Перейти до диспетчера завдань
  2. Знайдіть flask.exe
  3. Виберіть і завершіть процес

10
Кнопка живлення на вашому комп'ютері також досить ефективна ха-ха
Майкл Грін,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.