Ctrl-c kullanmadan balon uygulaması nasıl durdurulur


112

Flask-script kullanarak flask uygulamasını durdurabilecek bir komut uygulamak istiyorum. Çözümü bir süredir araştırdım. Çerçeve "app.stop ()" API sağlamadığından, bunu nasıl kodlayacağımı merak ediyorum. Ubuntu 12.10 ve Python 2.7.3 üzerinde çalışıyorum.


Neden uygulamanızı bir komut dosyasından durdurabilmeniz gerekiyor? (İş için en iyi araç, ne yapmaya çalıştığınıza bağlı olacaktır).
Sean Vieira

Cidden, burada ne yapmaya çalışıyorsun? Geliştirme için devserver'dan bahsediyorsanız, onu bu şekilde durdurmak gayet iyi. Üretimde bu şekilde dağıtım yapmazsınız ve bir isteği istediğiniz zaman durdurabilirsiniz, böylece "uygulama çalışmayı durdurur".
Ignas Butėnas

@SeanVieira Bunu yapmak için herhangi bir çözüm olup olmadığını bilmek istiyorum.
vic

@Yasemin Şu anda makinemde bir RESTful servisi geliştiriyorum. Bir proje üzerinde çalışıyorum, belki de hangi makineleri konuşlandırmam gerektiğini seçmeme yardımcı olur. Bunu çözebilmemin tek yolu, süreci sonlandırarak kapatmaktır.
vic

3
@vrootic, ancak zaten üretimde app.run () kullanmayacaksınız. app.run () yalnızca geliştirme için ve geliştirirken uygulamanızı test etmek için kullanılır. Flask'ı üretimde çalıştırmanın farklı yolları vardır, burada daha fazlası bulunabilir, örneğin flask.pocoo.org/docs/quickstart/#deploying-to-a-web-server Ve zaten böyle bir şekilde konuşlandırırsanız (bu yüzden yanlış anladım soru), Flask'a gelen istek sunmayı durdurmanın yolu, kendisine hizmet veren http sunucusunu durdurmaktır.
Ignas Butėnas

Yanıtlar:


135

Sunucuyu yalnızca masaüstünüzde çalıştırıyorsanız, sunucuyu sonlandırmak için bir uç nokta açığa çıkarabilirsiniz ( Basit Sunucuyu Kapatma bölümünde daha fazlasını okuyun ):

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

İşte daha kapsamlı olan başka bir yaklaşım:

from multiprocessing import Process

server = Process(target=app.run)
server.start()
# ...
server.terminate()
server.join()

Bunun yardımcı olup olmadığını bana bildirin.


18
Bir istek içeriğine ihtiyaç duymadan 'werkzeug.server.shutdown' özelliğini almanın bir yolu olup olmadığını biliyor musunuz?
akatkinson

5
Çalışması için rota yöntemini 'GET' olarak değiştirmem gerekiyordu.
CS

6
Tamlık için bu yanıt, kapatmayı yapmak için bir istek bağlamı dışında arayacağınız işlev eksik; bu, sunucuya bir HTTP isteğinden başka bir şey olmayacak (yerel ana bilgisayardan / yerel ana
makineden

1
İle methods='POST', bir 405 Method not allowedhata alıyorum, oysa yöntemlerle = 'GET'`, @CS'nin önerdiği şekilde çalışıyor.
Çevik Bean

1
AWS Elastic Beanstalk'ta benim için çalışmadı. Yerel olarak iyi çalıştı
Andrey Bulezyuk

36

Konuları kullanarak biraz farklı yaptım

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

Dinlendirici api için uçtan uca testler yapmak için kullanıyorum, burada python istek kitaplığını kullanarak istek gönderebilirim.


2
Diğer şeyleri çalıştırmayı başaramadım ama bu çözüm harika çalışıyor! Çok teşekkürler! Diğer insanlar için: aynı zamanda flask ile dinlendirici çalışır!
Jorrick Sleijster

Bu, başka bir istekle karşılayana kadar pencereleri engelliyor gibi görünüyor ... bunun etrafında herhangi bir şekilde?
Claudiu

Python 3.6.2 ile Linux dışında @Claudiu ile aynı sorunu yaşıyorum
micahscopes

Bunun neden kabul edilmediğini bilmiyorum, ancak en temiz gibi görünüyor ve ekstra bağımlılıklar olmadan harika çalışıyor. Çok teşekkürler.
Eric Reed

22

Bu biraz eski bir iş parçacığıdır, ancak temel flask uygulamasını deneyen, öğrenen veya test eden biri arka planda çalışan bir komut dosyasından başlamışsa, bunu durdurmanın en hızlı yolu uygulamanızı çalıştırdığınız bağlantı noktasında çalışan işlemi sonlandırmaktır. üzerinde. Not: Yazarın uygulamayı öldürmemek veya durdurmamak için bir yol aradığının farkındayım. Ancak bu, öğrenen birine yardımcı olabilir.

sudo netstat -tulnp | grep :5001

Bunun gibi bir şey alacaksın.

tcp 0 0 0.0.0.0:5001 0.0.0.0:* DİNLE 28834 / python

Uygulamayı durdurmak için işlemi sonlandırın

sudo kill 28834

sudo kill -9 28834İşlem öldürülmeden önce kullanmak zorunda kaldım .
Udo E.

17

Metoduma bash terminali / konsolu üzerinden devam edilebilir

1) çalıştırın ve işlem numarasını alın

$ ps aux | grep yourAppKeywords

2a) süreci sonlandırın

$ kill processNum

2b) yukarıda çalışmıyorsa işlemi sonlandırın

$ kill -9 processNum

10
Sorunun "bir işlemi nasıl öldürürüm" olmadığından neredeyse eminim ve sorun şu ki ctrl + c yapmak onu öldürmez. Btw, kullanıyorum kill -9 `lsof -i:5000 -t`çünkü sadece 1 uygulama bağlantı noktasını kullanamıyor ve kolay oluyor.
m3nda

10

Diğerlerinin de belirttiği gibi, yalnızca werkzeug.server.shutdownbir istek işleyicisinden kullanabilirsiniz. Sunucuyu başka bir zamanda kapatmanın tek yolu kendinize bir istek göndermektir. Örneğin,/kill bu kod parçasındaki işleyici, sonraki saniye içinde başka bir istek gelmedikçe geliştirici sunucusunu öldürecektir:

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

3
bu işe yarıyor ama hissediyor ... çok huysuz. Bir süredir biliyorum, ama kendinize bir istek göndermeden bunu yapmanın temiz bir yolunu buldunuz mu?
Juicy

7

Bu eski bir soru, ancak Google bunu nasıl başaracağım konusunda bana herhangi bir fikir vermedi.

Çünkü buradaki kodu düzgün okumadım ! (Doh!) Ne yapar bir yükseltmektir RuntimeErrorhiçbir yokken werkzeug.server.shutdownde request.environ...

Öyleyse, hiçbir requestşey olmadığında yapabileceğimiz şey,RuntimeError

def shutdown():
    raise RuntimeError("Server going down")

ve app.run()geri döndüğünde yakala :

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

Kendinize bir istek göndermenize gerek yok.


4

"CTRL-C" ye basmanız gerekmez, ancak bunu sizin için yapan bir uç nokta sağlayabilirsiniz:

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..." })

Artık sunucuyu zarif bir şekilde kapatmak için bu uç noktayı çağırabilirsiniz:

curl localhost:5000/stopServer

Kodunuzu test ettim, ancak daha sonra os.kill, dönen yanıt müşteri tarafından alınamıyor. Bunun için curl"curl: (56) Recv hatası: Bağlantı sıfırlandı" çıktıını verir. Ayrıca, Flask onu çözmek için yanıt döndürdükten sonra bir işlevi yürütme bölümüne de bakabilir .
samm

@samm, bu sorunun sonucu, farklı bir konu başlatmadığınız sürece bunun mümkün olmadığı, değil mi? Öyleyse, balon sunucusunu bu farklı iş parçacığından nasıl kapatırsınız?
Jurgy

2

Aşağıdaki yöntemi kullanabilirsiniz

app.do_teardown_appcontext()

Bu yanlış bir tahmin. Bu işlev uygulamayı durdurmaz, bireysel bir isteği işledikten sonra bazı içerikleri serbest bırakmak için otomatik olarak çağrılır. flask.palletsprojects.com/en/1.1.x/api/…
rgov

2

CLI üzerinde çalışıyorsanız ve çalışan yalnızca bir şişe uygulaması / işleminiz varsa (veya daha doğrusu, sisteminizde çalışan herhangi bir şişe işlemini öldürmek istiyorsanız ), onu şu şekilde öldürebilirsiniz:

kill $(pgrep -f flask)


1

İstek yanıtlama işleminin dışındaysanız, yine de şunları yapabilirsiniz:

import os
import signal

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

1

Başka biri win32 hizmeti içinde Flask sunucusunu nasıl durduracağını araştırıyorsa - işte burada. Birkaç yaklaşımın garip bir kombinasyonu, ancak iyi çalışıyor. Anahtar fikirler:

  1. Bunlar, shutdownnazikçe kapatma için kullanılabilen uç noktadır. Not : request.environ.getHangisinin yalnızca web isteğinin bağlamında kullanılabileceğine dayanır (iç @app.routeişlev)
  2. win32service'in SvcStopyöntemi requests, hizmetin kendisine HTTP isteği yapmak için kullanır .

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

0

Google Cloud sanal makine örneği + Flask Uygulaması

Flask Uygulamamı Google Cloud Platform Sanal Makinesinde barındırdım. Uygulamayı kullanarak başlattım python main.pyAma sorun ctrl + c sunucuyu durdurmak için işe yaramadı.

Bu komut $ sudo netstat -tulnp | grep :5000sunucuyu sonlandırır.

Flask uygulamam varsayılan olarak 5000 numaralı bağlantı noktasında çalışır.

Not: Sanal makine örneğim Linux 9'da çalışıyor.

Bunun için çalışıyor. Diğer platformlar için test edilmemiştir. Diğer sürümler için de çalışıyorsa güncellemekten veya yorum yapmaktan çekinmeyin.


0

Bir Python çözümü

İle çalıştırın: python kill_server.py.

Bu yalnızca Windows içindir . Netstat ile toplanan PID ile sunucuları taskkill ile öldürür.

# 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 yüklemesindeki değişikliklerle ilgili sorun yaşıyorsanız (yani eski sürümler önbelleğe alınır), o zaman Chrome'da "Tarama Verilerini Temizle> Resimler ve Dosyalar" seçeneğini de deneyin .

Yukarıdakilerin hepsini yaparak, Flask uygulamamı çalıştırdıktan sonra favicon'umu sonunda yükledim.


-3

Windows için, flask sunucusunu durdurmak / öldürmek oldukça kolaydır -

  1. Goto Görev Yöneticisi
  2. Flask.exe dosyasını bulun
  3. İşlemi Seç ve Bitir

14
Bilgisayarınızdaki güç düğmesi de oldukça etkili haha
Michael Green
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.