Hello Sir,
I wanted to use background callback in my multipage app which uses sqlachemy as orm. And I find it always fails under package “dill”.
Traceback (most recent call last):
File “”, line 1, in
File “E:\Documents\Github\lrp - Copy\venv\lib\site-packages\multiprocess\spawn.py”, line 116, in spawn_main
exitcode = _main(fd, parent_sentinel)
File “E:\Documents\Github\lrp - Copy\venv\lib\site-packages\multiprocess\spawn.py”, line 126, in _main
self = reduction.pickle.load(from_parent)
File “E:\Documents\Github\lrp - Copy\venv\lib\site-packages\dill_dill.py”, line 287, in load
return Unpickler(file, ignore=ignore, **kwds).load()
File “E:\Documents\Github\lrp - Copy\venv\lib\site-packages\dill_dill.py”, line 442, in load
obj = StockUnpickler.load(self)
EOFError: Ran out of input
I made a small app with two pages that can reproduce this issue:
app.py
import dash
from dash import Dash, html, dcc, DiskcacheManager, CeleryManager
import diskcache
cache = diskcache.Cache("./cache")
background_callback_manager = DiskcacheManager(cache)
app = Dash(__name__, use_pages=True, background_callback_manager=background_callback_manager)
app.layout = html.Div([
html.H1('Multi-page app with Dash Pages'),
dcc.Location(id='url', refresh=True),
html.Div([
html.Div(
dcc.Link(f"{page['name']} - {page['path']}", href=page["relative_path"])
) for page in dash.page_registry.values()
]),
dash.page_container
])
if __name__ == '__main__':
app.run(debug=True)
database.py
from sqlalchemy import create_engine
from sqlalchemy.orm import declarative_base
from sqlalchemy.orm import scoped_session, sessionmaker
engine = create_engine('postgresql://postgres:12345@server/db', pool_size=200, max_overflow=100, pool_recycle=3600, pool_pre_ping=True)
db_session = scoped_session(sessionmaker(autocommit=False,
autoflush=False,
bind=engine))
Base = declarative_base()
models.py
from sqlalchemy import Column, Integer, String
from database import Base
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String)
email = Column(String)
def __init__(self, **kwargs):
for key, value in kwargs.items():
setattr(self, key, value)
def __repr__(self):
return f'<User {self.name}>'
def __str__(self):
return self.name
pages/page1.py
import dash
from dash import html, callback, Input, Output, State, ctx
dash.register_page(__name__, path='/page1')
_name = __name__.split(".")[-1]
layout = html.Div([
html.Div(id=f"page_name_{_name}"),
html.H1(f'This is {_name}'),
html.Div(id=_name)
])
@callback(
Output(_name, "children"),
Input("url", "pathname"),
# prevent_initial_call=True,
)
def update_page_name(url):
return url
pages/page2.py
import time
import dash
from dash import html, callback, Input, Output
from database import db_session
from models import User
dash.register_page(__name__, path='/page2')
_name = __name__.split(".")[-1]
layout = html.Div(
[
html.Div(
[
html.P(id="paragraph_id", children=["Button not clicked"]),
html.Progress(id="progress_bar", value="0"),
]
),
html.Button(id="button_id", children="Run Job!"),
html.Button(id="cancel_button_id", children="Cancel Running Job!"),
]
)
@callback(
output=Output("paragraph_id", "children"),
inputs=Input("button_id", "n_clicks"),
background=True,
running=[
(Output("button_id", "disabled"), True, False),
(Output("cancel_button_id", "disabled"), False, True),
(
Output("paragraph_id", "style"),
{"visibility": "hidden"},
{"visibility": "visible"},
),
(
Output("progress_bar", "style"),
{"visibility": "visible"},
{"visibility": "hidden"},
),
],
cancel=Input("cancel_button_id", "n_clicks"),
progress=[Output("progress_bar", "value"), Output("progress_bar", "max")],
prevent_initial_call=True
)
def update_progress(set_progress, n_clicks):
total_records = db_session.query(User).all()
total = len(total_records)
for i in range(total + 1):
set_progress((str(i), str(total)))
time.sleep(0.1)
return f"Clicked {n_clicks} times"
The issue will occur when you click “Run Job” in page 2.
Here is my environment:
OS Win11 64bit
Python 3.10.2 I also tried with 3.11, it still fails.
Database: PostgreSQL 15
packages:
ansi2html==1.9.1
blinker==1.7.0
certifi==2023.11.17
charset-normalizer==3.3.2
click==8.1.7
colorama==0.4.6
dash==2.14.2
dash-core-components==2.0.0
dash-html-components==2.0.0
dash-table==5.0.0
dill==0.3.7
diskcache==5.6.3
Flask==3.0.0
idna==3.6
importlib-metadata==7.0.0
itsdangerous==2.1.2
Jinja2==3.1.2
MarkupSafe==2.1.3
multiprocess==0.70.15
nest-asyncio==1.5.8
packaging==23.2
plotly==5.18.0
psutil==5.9.7
requests==2.31.0
retrying==1.3.4
six==1.16.0
tenacity==8.2.3
typing_extensions==4.9.0
urllib3==2.1.0
Werkzeug==3.0.1
zipp==3.17.0
I found a similar issue: https://community.plotly.com/t/error-in-dash-multi-page-app-demos/70107/17 But I checked Github for dill it seems already a fix in 0.3.7. Now I don’t know if it’s a dash issue or my code issue.
Please help to advise.