webentwicklung-frage-antwort-db.com.de

Beim Starten des Unterthreads wird mit der Flasche "Außerhalb des Anforderungskontexts arbeiten" geworfen

Ich versuche, einen neuen Thread in Python in einer Flask-Anwendung zu starten. Ich mache Hintergrundarbeit, die durch die Anfrage ausgelöst wird, aber ich muss nicht warten, bis die Arbeit erledigt ist, um auf die Anfrage zu antworten.

Ist es möglich, die Flaschenanforderung in dieser untergeordneten Bedrohung für die eingegangene Anforderung festzulegen? Grund dafür ist, dass unsere Zugriffssteuerungsliste bei unseren Abfragen an unsere DB (mongoengine vor mongoDB) sich auf den Benutzer der Anforderung stützt (sie ruft ihn vom Anforderungsobjekt der Flasche ab), um zu sehen, ob sie Zugriff auf die Objekte haben, und deren Anblasen, weil die Anforderung vorliegt nicht im Unter-Thread verfügbar.

Alle Gedanken wären sehr dankbar.

Hier ist ein Pseudo-Code, wie ich damit umgehe, aber es funktioniert nicht.

@app.route('/my_endpoint', methods=['POST'])
def my_endpoint_handler():
    #do tracking in sub-thread so we don't hold up the page
    def handle_sub_view(req):
        from flask import request
        request = req
        # Do Expensive work
    thread.start_new_thread(handle_sub_view, (request))
    return "Thanks"
45
MattoTodd

Wickeln Sie Ihren Thread-Code in einen test_request_context, damit Sie auf Kontext-Locals zugreifen können:

@app.route('/my_endpoint', methods=['POST'])
def my_endpoint_handler():
    #do tracking in sub-thread so we don't hold up the page
    def handle_sub_view(req):
        with app.test_request_context():
            from flask import request
            request = req
            # Do Expensive work
    thread.start_new_thread(handle_sub_view, (request))
    return "Thanks"

Edit: Es ist darauf hinzuweisen, dass der Thread einen anderen Kontext hat als die ursprüngliche Anfrage. Sie müssen alle interessanten Anforderungsdaten wie die Benutzer-ID extrahieren, bevor Sie den Thread starten. Sie können dann mithilfe der ID ein (anderes) Benutzerobjekt im Unter-Thread abrufen.

57
Alex Morega

Seit Version 0.10 gibt es eine unterstützte Methode: http://flask.pocoo.org/docs/api/#flask.copy_current_request_context

Wenn die before_request-Hooks ausgeführt werden sollen, müssen Sie current_app.preprocess_request() in der dekorierten Funktion aufrufen.

30
runfalk

Sie können die gewünschte Information kopieren und weiterleiten:

@app.route('/my_endpoint', methods=['POST'])
def my_endpoint_handler():
    #do tracking in sub-thread so we don't hold up the page
    def handle_sub_view(data):
        # Use the data in subprocess
    data = request.get_json()  # copy the data
    thread.start_new_thread(handle_sub_view, data)
    return "Thanks"
5
vim

Wie @ runfalk darauf hinweist, müssen Sie @copy_current_request_context verwenden. Hier ist ein Funktionscode-Ausschnitt:

import threading

from flask import request, jsonify, copy_current_request_context


@app.route('/foo')
def get_foo():
    @copy_current_request_context
    def foo_main():
        # insert your code here
        print(request.url)

    threading.Thread(target=foo_main).start()

    return jsonify({'status': 'started'})
0
jrc