J'essaie de démarrer un nouveau thread en Python dans une application Flask. Je fais un travail en arrière-plan qui est déclenché par la demande, mais je n'ai pas besoin d'attendre que le travail soit fait pour répondre à la demande.
Est-il possible de définir la demande de flacon dans cette sous-menace par rapport à la demande reçue? Raison d'être, notre liste de contrôle d'accès sur nos requêtes à notre base de données (mongoengine devant mongoDB) repose sur l'utilisateur de la requête (il la récupère de l'objet requête du flask) pour voir s'il a accès aux objets non disponible dans le sous-fil.
Toute pensée serait très appréciée.
Voici le pseudo-code de la façon dont je le gère maintenant, mais cela ne fonctionne pas.
@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"
Enveloppez le code de votre fil dans un test_request_context
afin d’avoir accès à locals de contexte } _:
@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: il est intéressant de noter que le thread aura un contexte différent de celui de la requête d'origine. Vous devez extraire toutes les données de demande intéressantes, telles que l'ID utilisateur, avant de générer le thread. Vous pouvez ensuite récupérer un objet utilisateur (différent) dans le sous-fil à l'aide de l'ID.
Depuis la version 0.10, il existe un moyen de le faire: http://flask.pocoo.org/docs/api/#flask.copy_current_request_context
Si vous voulez que les hooks before_request
s'exécutent, vous devez appeler current_app.preprocess_request()
à l'intérieur de la fonction décorée.
Vous pouvez copier les informations souhaitées et les transmettre:
@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"
Comme @runfalk l'a signalé, vous devrez utiliser @copy_current_request_context
. Voici un extrait de code fonctionnel:
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'})