Flask throwing 'working outside of request context' when starting sub thread

后端 未结 5 1730
遇见更好的自我
遇见更好的自我 2020-11-30 21:23

I am trying to start a new thread in Python inside of a Flask application. I am doing background work that gets triggered by the request, but I don\'t need to wait for the

相关标签:
5条回答
  • 2020-11-30 21:43

    Since version 0.10 there is a supported way of doing this: http://flask.pocoo.org/docs/api/#flask.copy_current_request_context

    If you want the before_request hooks to run you must call current_app.preprocess_request() inside of the decorated function.

    0 讨论(0)
  • 2020-11-30 21:47

    As @runfalk pointed out, you'll need to use @copy_current_request_context. Here's a working code snippet:

    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 讨论(0)
  • 2020-11-30 21:55

    You can copy the desired info and pass it on:

    @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 讨论(0)
  • 2020-11-30 21:55

    A more cleaner way is using Flask built-in executor which wraps app context, see https://flask-executor.readthedocs.io/en/latest/

    0 讨论(0)
  • 2020-11-30 22:04

    Wrap your thread code in a test_request_context so you have access to 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"
    

    Edit: it's worth pointing out that the thread will have a different context than the original request. You need to extract any interesting request data, such as the user ID, before spawning the thread. You can then grab a (different) user object in the sub-thread using the ID.

    0 讨论(0)
提交回复
热议问题