Як зупинити застосування колби без використання 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.