Dash Background Callbacks与SQLAlchemy兼容异常求助
问题
使用Dash 2.6.1,尝试让Background Callbacks与SQLAlchemy协同工作。在官方教程的第一个示例中添加from sqlalchemy import create_engine语句后,点击网页上的Run Job!按钮触发sqlite3.OperationalError: disk I/O error错误。
代码示例
from sqlalchemy import create_engine # This breaks Dash. import time import os import dash from dash import DiskcacheManager, CeleryManager, Input, Output, html if 'REDIS_URL' in os.environ: # Use Redis & Celery if REDIS_URL set as an env variable from celery import Celery celery_app = Celery(__name__, broker=os.environ['REDIS_URL'], backend=os.environ['REDIS_URL']) background_callback_manager = CeleryManager(celery_app) else: # Diskcache for non-production apps when developing locally import diskcache cache = diskcache.Cache("./cache") background_callback_manager = DiskcacheManager(cache) app = dash.Dash(__name__) app.layout = html.Div( [ html.Div([html.P(id="paragraph_id", children=["Button not clicked"])])], html.Button(id="button_id", children="Run Job!"), ] ) @dash.callback( output=Output("paragraph_id", "children"), inputs=Input("button_id", "n_clicks"), background=True, manager=background_callback_manager, ) def update_clicks(n_clicks): time.sleep(2.0) return [f"Clicked {n_clicks} times"] if __name__ == "__main__": app.run_server(debug=True)
报错信息
Dash is running on http://127.0.0.1:8050/ * Serving Flask app 'main' * Debug mode: on Process Process-3: Traceback (most recent call last): File "/Users/one/.pyenv/versions/live/lib/python3.9/site-packages/multiprocess/process.py", line 315, in _bootstrap self.run() File "/Users/one/.pyenv/versions/live/lib/python3.9/site-packages/multiprocess/process.py", line 108, in run self._target(*self._args, **self._kwargs) File "/Users/one/.pyenv/versions/live/lib/python3.9/site-packages/dash/long_callback/managers/diskcache_manager.py", line 179, in job_fn cache.set(result_key, user_callback_output) File "/Users/one/.pyenv/versions/live/lib/python3.9/site-packages/diskcache/core.py", line 796, in set with self._transact(retry, filename) as (sql, cleanup): File "/Users/one/.pyenv/versions/3.9.9/lib/python3.9/contextlib.py", line 119, in __enter__ return next(self.gen) File "/Users/one/.pyenv/versions/live/lib/python3.9/site-packages/diskcache/core.py", line 710, in _transact sql = self._sql File "/Users/one/.pyenv/versions/live/lib/python3.9/site-packages/diskcache/core.py", line 648, in _sql return self._con.execute File "/Users/one/.pyenv/versions/live/lib/python3.9/site-packages/diskcache/core.py", line 623, in _con con = self._local.con = sqlite3.connect( sqlite3.OperationalError: disk I/O error
解决方案
这不是Dash的Bug,根源是SQLAlchemy导入后会修改全局sqlite3的连接配置,导致diskcache使用的sqlite3连接出现资源冲突。可通过以下方式解决:
延迟导入SQLAlchemy:不在全局作用域导入
create_engine,而是在实际需要使用它的函数内部导入。比如把SQLAlchemy相关操作放在回调函数里:def update_clicks(n_clicks): from sqlalchemy import create_engine # 这里执行SQLAlchemy相关逻辑 time.sleep(2.0) return [f"Clicked {n_clicks} times"]调整diskcache的sqlite连接参数:初始化diskcache时,指定SQLiteDisk并设置超时时间,避免连接阻塞:
import diskcache from diskcache import SQLiteDisk cache = diskcache.Cache("./cache", disk=SQLiteDisk, timeout=30)切换到Celery+Redis后台:如果有条件部署Redis,直接使用CeleryManager替代DiskcacheManager,彻底避开sqlite3的冲突问题。
内容的提问来源于stack exchange,提问作者Jon
相关产品推荐
相关产品推荐

