Ich schreibe eine Anwendung in Flask, die sehr gut funktioniert, außer dass sie WSGI
synchron und blockierend ist. Ich habe insbesondere eine Aufgabe, die eine Drittanbieter-API aufruft, und diese Aufgabe kann einige Minuten dauern. Ich möchte diesen Anruf tätigen (es ist eigentlich eine Reihe von Anrufen) und ihn laufen lassen. während die Kontrolle an Flask zurückgegeben wird.
Meine Ansicht sieht aus wie:
@app.route('/render/<id>', methods=['POST'])
def render_script(id=None):
...
data = json.loads(request.data)
text_list = data.get('text_list')
final_file = audio_class.render_audio(data=text_list)
# do stuff
return Response(
mimetype='application/json',
status=200
)
Was ich jetzt tun möchte, ist die Leitung zu haben
final_file = audio_class.render_audio()
Führen Sie einen Rückruf aus und stellen Sie ihn bereit, der ausgeführt werden soll, wenn die Methode zurückgegeben wird, während Flask weiterhin Anforderungen verarbeiten kann. Dies ist die einzige Aufgabe, die Flask asynchron ausführen muss, und ich möchte einige Ratschläge, wie dies am besten implementiert werden kann.
Ich habe mir Twisted und Klein angesehen, bin mir aber nicht sicher, ob sie übertrieben sind, da Threading vielleicht ausreichen würde. Oder ist Sellerie dafür eine gute Wahl?
quelle
Antworten:
Ich würde Sellerie verwenden , um die asynchrone Aufgabe für Sie zu erledigen. Sie müssen einen Broker installieren, der als Aufgabenwarteschlange dient (RabbitMQ und Redis werden empfohlen).
app.py
::Führen Sie Ihre Flask-App aus und starten Sie einen weiteren Prozess, um Ihren Sellerie-Arbeiter auszuführen.
Ich verweise auch auf Miguel Gringberg die bis zu schreiben für eine mehr in die Tiefe Anleitung zur Verwendung von Sellerie mit Flask.
quelle
Einfädeln ist eine weitere mögliche Lösung. Obwohl die auf Sellerie basierende Lösung für skalierte Anwendungen besser geeignet ist, ist Threading eine praktikable Alternative, wenn Sie nicht zu viel Datenverkehr auf dem betreffenden Endpunkt erwarten.
Diese Lösung basiert auf Miguel Grinbergs PyCon 2016 Flask at Scale-Präsentation , insbesondere Folie 41 in seinem Dia-Deck. Sein Code ist auch auf Github für diejenigen verfügbar, die an der Originalquelle interessiert sind.
Aus Anwendersicht funktioniert der Code wie folgt:
Um einen API-Aufruf in eine Hintergrundaufgabe zu konvertieren, fügen Sie einfach den @ async_api-Dekorator hinzu.
Hier ist ein vollständig enthaltenes Beispiel:
quelle
Sie können auch versuchen,
multiprocessing.Process
mit zu verwendendaemon=True
; Dieprocess.start()
Methode blockiert nicht und Sie können eine Antwort / einen Status sofort an den Aufrufer zurückgeben, während Ihre teure Funktion im Hintergrund ausgeführt wird.Ich hatte ein ähnliches Problem, als ich mit dem Falcon Framework arbeitete und den
daemon
Prozess half.Sie müssten Folgendes tun:
Sie sollten sofort eine Antwort erhalten und nach 10 Sekunden sollte eine gedruckte Nachricht in der Konsole angezeigt werden.
HINWEIS: Beachten Sie, dass
daemonic
Prozesse keine untergeordneten Prozesse erzeugen dürfen.quelle
/render/<id>
Endpunkt etwas erwartetmy_func()
?my_func
Antwort / einen Herzschlag an einen anderen Endpunkt senden. Oder Sie können eine Nachrichtenwarteschlange einrichten und freigeben, über die Sie kommunizieren könnenmy_func