简体   繁体   中英

Why child threads cannot access the current_user variable in flask_login?

I am writing a Flask application and I am trying to insert a multi-threaded implementation for certain server related features. I noticed this weird behavior so I wanted to understand why is it happening and how to solve it. I have the following code:

from flask_login import current_user, login_required
import threading

posts = Blueprint('posts', __name__)

@posts.route("/foo")
@login_required
def foo():
    print(current_user)
    thread = threading.Thread(target=goo)
    thread.start()
    thread.join()
    return


def goo():
    print(current_user)
    # ...

The main process correctly prints the current_user , while the child thread prints None .

User('Username1', 'email1@email.com', 'Username1-ProfilePic.jpg')
None

Why is it happening? How can I manage to obtain the current_user also in the child process? I tried passing it as argument of goo but I still get the same behavior.

I found this post but I can't understand how to ensure the context is not changing in this situation, so I tried providing a simpler example.

A partially working workaround

I tried passing as parameter also a newly created object User populated with the data from current_user

def foo():
    # ...
    user = User.query.filter_by(username=current_user.username).first_or_404()
    thread = threading.Thread(target=goo, args=[user])
    # ...

def goo(user):
    print(user)
    # ...

And it correctly prints the information of the current user. But since inside goo I am also performing database operations I get the following error:

RuntimeError: No application found. Either work inside a view function or push an application context. See http://flask-sqlalchemy.pocoo.org/contexts/ .

So as I suspected I assume it's a problem of context.

I tried also inserting this inside goo as suggested by the error:

def goo():
    from myapp import create_app
    app = create_app()
    app.app_context().push()
    # ... database access

But I still get the same errors and if I try to print current_user I get None .

How can I pass the old context to the new thread? Or should I create a new one?

This is because Flask uses thread local variables to store this for each request's thread. That simplifies in many cases, but makes it hard to use multiple threads. Seehttps://flask.palletsprojects.com/en/1.1.x/design/#thread-local .

If you want to use multiple threads to handle a single request, Flask might not be the best choice. You can always interact with Flask exclusively on the initial thread if you want and then forward anything you need on other threads back and forth yourself through a shared object of some kind. For database access on secondary threads, you can use a thread-safe database library with multiple threads as long as Flask isn't involved in its usage.

In summary, treat Flask as single threaded. Any extra threads shouldn't interact directly with Flask to avoid problems. You can also consider either not using threads at all and run everything sequentially or trying eg Tornado and asyncio for easier concurrency with coroutines depending on the needs.

your server serves multiple users, wich are threads by themself. flask_login was not designed for extra threading in it, thats why child thread prints None.

i suggest u to use db for transmit variables from users and run addition docker container if you need separate process.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM