Подтвердить что ты не робот

Flocks throwing "работает вне контекста запроса" при запуске подпотока

Я пытаюсь запустить новый поток в Python внутри приложения Flask. Я выполняю фоновую работу, вызванную запросом, но мне не нужно ждать выполнения работы, чтобы ответить на запрос.

Можно ли задать запрос колбы в этой под-угрозе на запрос, который пришел? Причина в том, что наш ACL по нашим запросам нашей БД (mongoengine перед mongoDB) опирается на пользователя запроса (он захватывает его из объекта запроса на флягу), чтобы узнать, имеют ли они доступ к объектам, и его раздутие, потому что запрос недоступен в подпотоке.

Любые мысли будут высоко оценены.

Здесь псевдо-код того, как я обрабатываю его сейчас, но он не работает.

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

Ответ 1

Оберните код потока в test_request_context, чтобы у вас был доступ к локалям контекста:

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

Изменить: стоит отметить, что поток будет иметь другой контекст, чем исходный запрос. Перед созданием потока вам нужно извлечь любые интересные данные запроса, например идентификатор пользователя. Затем вы можете захватить (другой) пользовательский объект в подпотоке с помощью идентификатора.

Ответ 2

Начиная с версии 0.10 существует поддерживаемый способ: http://flask.pocoo.org/docs/api/#flask.copy_current_request_context

Если вы хотите, чтобы хосты before_request запускались, вы должны вызвать current_app.preprocess_request() внутри декорированной функции.

Ответ 3

Вы можете скопировать нужную информацию и передать ее:

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

Ответ 4

Как отметил @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'})