启动子线程时抛出烧瓶‘在请求上下文之外工作’

我试图在 Flask 应用程序内部用 Python 启动一个新线程。我正在进行由请求触发的后台工作,但是我不需要等待工作完成以响应请求。

是否可以将这个子威胁中的烧瓶请求设置为传入的请求?原因是,我们对 DB (mongoDB 前面的 mongoengine)的查询的 ACL 依赖于请求的用户(它从 flask 的请求对象抓取它)来查看他们是否有访问对象的权限,并且由于请求在子线程中不可用而导致其崩溃。

如果你有任何想法,我将不胜感激。

下面是我现在如何处理它的伪代码,但它不工作。

@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"
107465 次浏览

Wrap your thread code in a test_request_context so you have access to 当地人:

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

编辑 : 值得指出的是,线程将具有与原始请求不同的上下文。在生成线程之前,需要提取任何有趣的请求数据,比如用户 ID。然后,您可以使用 ID 在子线程中获取(不同的)用户对象。

自0.10版以来,有一种支持这样做的方法: http://flask.pocoo.org/docs/api/#flask.copy_current_request_context

如果要运行 before_request挂钩,必须在修饰函数内调用 current_app.preprocess_request()

你可以复制想要的信息并传递下去:

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

正如@runfalk 指出的,您需要使用 @copy_current_request_context:

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'})

更简洁的方法是使用 Flask 内置的执行器,它包装应用程序上下文,参见 https://flask-executor.readthedocs.io/en/latest/