当应用工厂模式使用时,为什么flask应用上下文在子线程中丢失?



有点神秘。

当所有代码都放在单个app.py文件中时,从flask app中生成一个线程工作得很好,但是当使用工厂模式时,应用程序上下文会丢失。

Exception in thread Thread-2:
Traceback (most recent call last):
File "/XXX/flaskthreading/venv/lib/python3.9/site-packages/sqlalchemy/util/_collections.py", line 1008, in __call__
127.0.0.1 - - [07/Jun/2022 14:06:53] "GET / HTTP/1.1" 200 -
return self.registry[key]
KeyError: <greenlet.greenlet object at 0x7f4f541ad040 (otid=0x7f4f54199d00) current active started main>
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/lib/python3.9/threading.py", line 954, in _bootstrap_inner
self.run()
File "/usr/lib/python3.9/threading.py", line 892, in run
self._target(*self._args, **self._kwargs)
File "/XXX/flaskthreading/app2/views.py", line 12, in printer
print(User.query.all())
File "/XXX/flaskthreading/venv/lib/python3.9/site-packages/flask_sqlalchemy/__init__.py", line 552, in __get__
return type.query_class(mapper, session=self.sa.session())
File "/XXX/flaskthreading/venv/lib/python3.9/site-packages/sqlalchemy/orm/scoping.py", line 47, in __call__
sess = self.registry()
File "/XXX/flaskthreading/venv/lib/python3.9/site-packages/sqlalchemy/util/_collections.py", line 1010, in __call__
return self.registry.setdefault(key, self.createfunc())
File "/XXX/flaskthreading/venv/lib/python3.9/site-packages/sqlalchemy/orm/session.py", line 4225, in __call__
return self.class_(**local_kw)
File "/XXX/flaskthreading/venv/lib/python3.9/site-packages/flask_sqlalchemy/__init__.py", line 174, in __init__
self.app = app = db.get_app()
File "/XXX/flaskthreading/venv/lib/python3.9/site-packages/flask_sqlalchemy/__init__.py", line 1042, in get_app
raise RuntimeError(
RuntimeError: No application found. Either work inside a view function or push an application context. See http://flask-sqlalchemy.pocoo.org/contexts/.

知道为什么会发生这种情况,或者我们错过了什么文档吗?MVP提供https://github.com/bodik/flaskthreading-experiments/

git clone
pip install -r requirements.txt
# working app
FLASK_APP=app1 flask run
curl http://localhost:5000/
# produces error
FLASK_APP=app2.app flask run
curl http://localhost:5000/

From https://flask.palletsprojects.com/en/2.1.x/reqcontext/#lifetime-of-the-context:

当一个Flask应用程序开始处理一个请求时,它会推送一个请求上下文,这个请求上下文也会推送一个应用上下文。当请求结束时,它先弹出请求上下文,然后弹出应用程序上下文。

上下文对于每个线程(或其他worker类型)是唯一的. ...

在全局appdb = SQLAlchemy(app)的情况下,db总是有self.app
在应用程序工厂模式的情况下,db从线程获取应用程序上下文

传递一个AppContext到线程:

# def printer():           # Change this
def printer(app_context):  # to this
app_context.push()     #
print(User.query.all())
@blueprint.route('/')
def index():
# athread = Thread(target=printer, args=(), daemon=True)                          # Change this
athread = Thread(target=printer, args=(current_app.app_context(),), daemon=True)  # to this
athread.start()
return 'ok'

最新更新