webentwicklung-frage-antwort-db.com.de

Führen Sie den Code aus, nachdem die Flaschenanwendung gestartet wurde

Mein Ziel ist es, beliebigen Code nach dem Start meiner Flask-Anwendung auszuführen. Hier ist was ich habe:

def run():
    from webapp import app
    app.run(debug=True, use_reloader=False)

Idealerweise würde ich das einfach tun können:

def run():
    from webapp import app
    app.run(debug=True, use_reloader=False)
    some_code()

Der Code wird jedoch nicht an app.run() weitergegeben, so dass some_code () niemals ausgeführt wird.

Die Lösung, an der ich gerade arbeite, besteht darin, some_code () in einem separaten Thread von app.run () auszuführen. Erstellen Sie eine vor der ersten Anforderung - Funktion, die Folgendes festlegt: 

app.is_running = True

Dann holen Sie sich some_code (), um eine grundlegende Anfrage an die App zu senden, sodass der Code "vor der ersten Anfrage" ausgeführt wird. Dies ist ziemlich kompliziert und wird schwer zu dokumentieren sein. Ich würde eher den app.is_running -Parameter verwenden, der bereits in Flask enthalten ist, oder einen @app.after_server_start-Dekorator verwenden, aber meines Wissens existiert keiner der beiden.

Helfen Sie mir, diesen Code besser zu machen?


Posthum: Jedes Mal, wenn ich über dieses Problem nachdenke, möchte ich, dass es einen @app.after_server_start-Dekorateur gibt.

27
Cyrin

Wenn Sie Code ausführen müssen, nachdem Ihre Flaschenanwendung strikt vor der ersten Anforderung gestartet wurde, wird sie nicht einmal durch die Ausführung der ersten Anforderung ausgelöst, da @ app.before_first_request sie verarbeiten kann. Sie sollten jedoch Flask_Script verwenden, wie CESCO sagte Könnte die Klasse Server Unterklassen und die __call_ Methode überschreiben, anstatt den runserver-Befehl mit @ manager.command zu überschreiben:

from flask import Flask
from flask_script import Manager, Server

def custom_call():
    #Your code
    pass

class CustomServer(Server):
    def __call__(self, app, *args, **kwargs):
        custom_call()
        #Hint: Here you could manipulate app
        return Server.__call__(self, app, *args, **kwargs)

app = Flask(__name__)
manager = Manager(app)

# Remeber to add the command to your Manager instance
manager.add_command('runserver', CustomServer())

if __== "__main__":
    manager.run()

Auf diese Weise überschreiben Sie die Standardoptionen des Befehls runserver nicht.

20
Ismael

Verwenden Sie Flask-Script , um Ihre App auszuführen, und überschreiben Sie dann die Runserver-Klasse/-Methode auf diese Weise

# manage.py

from flask.ext.script import Manager

from myapp import app

manager = Manager(app)

def crazy_call():
    print("crazy_call")

@manager.command
def runserver():
    app.run()
    crazy_call()

if __== "__main__":
    manager.run()
9
CESCO

Ich habe gerade (in einem main.py Mit python main.py Ausgeführt):

with app.app_context():
    from module import some_code()
    some_code()

def run():
    from webapp import app
    app.run(debug=True, use_reloader=False)

Dies funktionierte für mich ohne die oben angebotenen umfassenderen Antworten. In meinem Fall initialisiert some_code() einen Cache über flask_caching.Cache.

Aber es hängt wahrscheinlich davon ab, was genau some_code Tut ...

2
jtlz2

Dieses Problem ist mir in einer Flaschen-App von mir begegnet. Ich wollte beim Start der App einen Scheduler starten, der in regelmäßigen Abständen einige Jobs starten würde. Da ich meine Apps in Docker-Containern bereitstelle, habe ich am Ende einen Endpoint "Health Check" hinzugefügt, der nur eine 200 zurückgibt, und in meinem Dockerfile wurde dieser Endpoint konfiguriert:

HEALTHCHECK CMD curl --fail http://localhost:8080/alive || exit 1

Das Standardverhalten besteht darin, diesen Befehl alle 30 Sekunden auszuführen, und der erste Durchlauf startet bequem meine Methode init () https://docs.docker.com/engine/reference/builder/#healthcheck

0
skelly

Ich mag keine der oben genannten Methoden wirklich, da Sie dazu kein Flask-Script benötigen und nicht alle Projekte bereits Flask-Script verwenden.

Die einfachste Methode wäre, eine eigene Flask Unterklasse zu erstellen. Wenn Sie Ihre App mit Flask(__name__) erstellen, fügen Sie einfach Ihre eigene Klasse hinzu und verwenden sie stattdessen.

def do_something():
  print('MyFlaskApp is starting up!')


class MyFlaskApp(Flask):
  def run(self, Host=None, port=None, debug=None, load_dotenv=True, **options):
    if not self.debug or os.getenv('WERKZEUG_RUN_MAIN') == 'true':
      with self.app_context():
        do_something()
    super(MyFlaskApp, self).run(Host=host, port=port, debug=debug, load_dotenv=load_dotenv, **options)


app = MyFlaskApp(__name__)
app.run()

Natürlich läuft das nicht nach es startet, aber richtig vorrun() wird endlich aufgerufen. Mit dem App-Kontext sollten Sie in der Lage sein, alles zu tun, was Sie für die Datenbank oder für alles andere, was den App-Kontext erfordert, benötigen. Dies sollte auch mit jedem Server (uwsgi, gunicorn usw.) funktionieren.

Wenn Sie möchten, dass die do_something() nicht blockiert, können Sie sie stattdessen einfach mit threading.Thread(target=do_something).start() fädeln.

Die bedingte Anweisung soll den doppelten Aufruf verhindern, wenn der Debug-Modus/Reloader verwendet wird.

0
jslay