2012-03-29 9 views
36

Ich versuche, einen neuen Thread in Python innerhalb einer Flask-Anwendung zu starten. Ich mache Hintergrundarbeit, die von der Anfrage ausgelöst wird, aber ich muss nicht warten, bis die Arbeit erledigt ist, um auf die Anfrage zu antworten.Flask werfend "außerhalb des Anfragekontexts arbeiten" beim Starten von Unter-Thread

Ist es möglich, die Flaschenanforderung in dieser Subbedrohung auf die eingehende Anfrage zu setzen? Der Grund dafür ist, dass unsere ACL auf unsere Anfragen an unsere DB (Mongoengine vor mongoDB) auf den Benutzer der Anfrage angewiesen ist (er nimmt es aus dem Anfrageobjekt von flask), um zu sehen, ob sie Zugriff auf die Objekte haben und dass die Anfrage explodiert nicht im Unter-Thread verfügbar.

Alle Gedanken würden sehr geschätzt werden.

Hier ist Pseudo-Code, wie ich es jetzt handle, 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" 
+1

passieren Wenn Sie nur die Benutzer benötigen, warum dann nicht nur den Benutzer in das Gewinde Unter passieren? –

+0

flask bietet jederzeit Zugriff auf die Anforderung, sodass meine Document-Basisklasse über einen Abfrage-Set-Manager verfügt, der den Benutzer von der Anfrage abruft. Die Arbeit, die ich mache, ist viel höher als die Abfrage-Set-Manager, so kann ich nicht einfach den Benutzer selbst verwenden – MattoTodd

+0

Die Anfrage ist ein Thread/Kontext lokal, so dass es nicht verfügbar ist * anytime sonst hätten Sie dieses Problem nicht . Ich denke immer noch, dass Sie versuchen sollten, die Abhängigkeit vom Anforderungsobjekt neu zu definieren. –

Antwort

44

Wickeln Sie Ihre Thread-Code in einem test_request_context so haben Sie Zugriff auf context locals:

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

bearbeiten: es ist erwähnenswert, dass der Thread einen anderen Kontext als die ursprüngliche Anforderung haben. Sie müssen alle interessanten Anforderungsdaten wie die Benutzer-ID extrahieren, bevor Sie den Thread erstellen. Sie können dann ein (anderes) Benutzerobjekt im Unter-Thread mit der ID erfassen.

+2

Sie können auch versuchen, dies zu abstrahieren - http://celeryproject.org/ Ich verwende es zum Blockieren von Operationen wie das Senden von E-Mails. Die gute Sache ist, dass Sie mongoDB als Backend verwenden können, also müssen Sie nichts zu Ihrem Stack hinzufügen. – Ross

4

können Sie die gewünschte Info kopieren und

@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" 
+0

ist es nicht praktisch. Ich muss alle Daten über App kopieren. – jamlee