Como parar a aplicação do frasco sem usar ctrl-c


102

Eu quero implementar um comando que pode interromper a aplicação de flask usando flask-script. Há algum tempo procuro a solução. Como a estrutura não fornece a API "app.stop ()", estou curioso para saber como codificar isso. Estou trabalhando no Ubuntu 12.10 e Python 2.7.3.


Por que você precisa ser capaz de interromper seu aplicativo a partir de um script? (A melhor ferramenta para o trabalho dependerá do que você está tentando fazer).
Sean Vieira

Sério, o que você está tentando fazer aqui? Se você está falando sobre devserver para desenvolvimento, é perfeitamente normal pará-lo assim. Na produção, você não implanta assim e pode interromper uma solicitação a qualquer momento que quiser, para que o "aplicativo pare de funcionar"
Ignas Butėnas,

@SeanVieira Quero saber se existe alguma solução para fazer isso.
vic

@IgnasB. Estou desenvolvendo um serviço RESTful em minha máquina agora. Estou trabalhando em um projeto que talvez me ajude a escolher quais máquinas devo implantar. A única maneira de descobrir isso é encerrando o processo.
vic

3
@vrootic, mas você não usará app.run () na produção de qualquer maneira. app.run () é usado apenas para desenvolvimento e para testar seu aplicativo durante o desenvolvimento. Existem diferentes maneiras de executar o Flask em produção, mais podem ser encontradas aqui, por exemplo flask.pocoo.org/docs/quickstart/#deploying-to-a-web-server E se você já implantar de alguma forma assim (então eu entendi mal questão), a maneira de parar de atender a solicitação que chega ao Flask é parar o servidor http que está servindo.
Ignas Butėnas

Respostas:


121

Se você está apenas executando o servidor em seu desktop, pode expor um endpoint para encerrar o servidor (leia mais em 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...'

Aqui está outra abordagem que é mais contida:

from multiprocessing import Process

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

Avise-me se isso ajudar.


15
Você sabe se há alguma maneira de obter a propriedade 'werkzeug.server.shutdown' sem a necessidade de um contexto de solicitação?
akatkinson

5
Tive que alterar o método de rota para 'GET' para fazê-lo funcionar.
CS

5
Para completar, esta resposta está faltando a função que você chamaria fora de um contexto de solicitação para fazer o desligamento, que seria nada mais do que uma solicitação HTTP para o servidor (que pode se originar de / para localhost)
JamesHutchison

1
Com methods='POST', recebo um 405 Method not allowederro, enquanto que com métodos = 'GET'`, funciona como @CS sugerido.
Agile Bean

1
Não funcionou para mim no AWS Elastic Beanstalk. Funcionou bem localmente
Andrey Bulezyuk

34

Fiz um pouco diferente usando tópicos

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

Eu o uso para fazer testes de ponta a ponta para api restful, onde posso enviar solicitações usando a biblioteca de solicitações python.


2
Não consegui fazer as outras coisas funcionarem, mas esta solução funciona muito bem! Muito obrigado! Para as outras pessoas: também funciona com frasco repousante!
Jorrick Sleijster

Isso parece bloquear no windows até que eu acertei com outro pedido ... alguma maneira de contornar isso?
Claudiu

Estou tendo o mesmo problema que @Claudiu, exceto no Linux com python 3.6.2
micahscopes

Não sei por que isso não é aceito, mas parece ser o mais limpo e funciona muito bem sem nenhuma dependência extra. Muito obrigado.
Eric Reed

17

Este é um tópico um pouco antigo, mas se alguém experimentando, aprendendo ou testando o aplicativo básico do flask, começou a partir de um script executado em segundo plano, a maneira mais rápida de interrompê-lo é encerrar o processo em execução na porta em que você está executando o aplicativo em. Nota: Estou ciente de que o autor está procurando uma maneira de não matar ou parar o aplicativo. Mas isso pode ajudar alguém que está aprendendo.

sudo netstat -tulnp | grep :5001

Você obterá algo assim.

tcp 0 0 0.0.0.0:5001 0.0.0.0:* LISTEN 28834 / python

Para parar o aplicativo, interrompa o processo

sudo kill 28834

14

Meu método pode ser executado via terminal / console bash

1) execute e obtenha o número do processo

$ ps aux | grep yourAppKeywords

2a) matar o processo

$ kill processNum

2b) interromper o processo se acima não funcionar

$ kill -9 processNum

9
Tenho quase certeza de que a questão não é "como matar um processo", e o problema é que fazer ctrl + c não o mata. A propósito, eu uso kill -9 `lsof -i:5000 -t`porque nenhum outro além de um aplicativo pode usar a porta e está sendo fácil.
m3nda

9

Como outros apontaram, você só pode usar a werkzeug.server.shutdownpartir de um manipulador de solicitações. A única maneira que encontrei de desligar o servidor em outro momento é enviar uma solicitação para você mesmo. Por exemplo, o /killmanipulador neste snippet eliminará o servidor de desenvolvimento, a menos que outra solicitação chegue durante o próximo segundo:

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
isso funciona, mas parece ... muito hacky. Eu sei que já faz um tempo, mas você já encontrou uma maneira limpa de fazer isso, sem enviar um pedido a si mesmo?
Juicy

7

Esta é uma pergunta antiga, mas pesquisar no Google não me deu nenhuma ideia de como fazer isso.

Porque eu não li o código aqui corretamente! (Doh!) O que faz é levantar um RuntimeErrorquando não há werkzeug.server.shutdownno request.environ...

Então, o que podemos fazer quando não há requesté levantar umRuntimeError

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

e pegue isso quando app.run()retornar:

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

Não há necessidade de enviar um pedido a si mesmo.


4

Você não precisa pressionar "CTRL-C", mas pode fornecer um ponto de extremidade que faz isso para você:

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

Agora você pode simplesmente chamar este endpoint para desligar o servidor normalmente:

curl localhost:5000/stopServer

Testei seu código, mas depois os.kill, a resposta retornada não pode ser recebida pelo cliente. Para curl, ele produz "curl: (56) Falha de recebimento: a conexão foi reiniciada". Pode ver também Executar uma função após o Flask retornar uma resposta para resolvê-lo.
samm

@samm, a conclusão dessa pergunta é que não é possível a menos que você comece um tópico diferente, certo? Então, como você fecha o servidor do flask desse thread diferente?
Jurgy

3

Você pode usar o método abaixo

app.do_teardown_appcontext()

2

Se você estiver trabalhando na CLI e tiver apenas um aplicativo / processo flask em execução (ou melhor, se quiser apenas matar qualquer processo flask em execução no seu sistema), poderá eliminá-lo com:

kill $(pgrep -f flask)


1

Se você estiver fora do tratamento de solicitação-resposta, ainda pode:

import os
import signal

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

1

Instância de VM do Google Cloud + aplicativo Flask

Hospedei meu aplicativo Flask na máquina virtual do Google Cloud Platform. Iniciei o aplicativo usando python main.pyMas o problema era ctrl + c não funcionou para parar o servidor.

Este comando $ sudo netstat -tulnp | grep :5000termina o servidor.

Meu aplicativo Flask é executado na porta 5000 por padrão.

Observação: minha instância de VM está sendo executada no Linux 9.

Funciona para isso. Não testei para outras plataformas. Sinta-se à vontade para atualizar ou comentar se funcionar também para outras versões.


-1

Para Windows, é muito fácil parar / encerrar o servidor Flask -

  1. Ir para o Gerenciador de Tarefas
  2. Encontre flask.exe
  3. Selecione e termine o processo

9
O botão
Michael Green
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.