Long callback function executed without being triggered in Dash Pages with Background callback
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 24.4k
- Forks
- 2.3k
- Avg merge
- 2d 7h
- Merged PRs (30d)
- 13
Description
Background callback works fine with Dash Pages. However, if we use a dcc.Store() (defined in the app.py) as an Output in the background callback, a long callback function is executed upon page load without being triggered.
[2022-12-21 18:54:55,564: INFO/MainProcess] Task long_callback_145c7444e8da7496daf8e16142713cc0c5b46902[224f59f9-aabe-4e60-942b-16f23fad09ee] received
[2022-12-21 18:54:57,582: INFO/ForkPoolWorker-1] Task long_callback_145c7444e8da7496daf8e16142713cc0c5b46902[224f59f9-aabe-4e60-942b-16f23fad09ee] succeeded in 2.0161583395674825s: None
I have attached a sample app to reproduce this issue.
app.py
from dash import Dash, html, dcc, DiskcacheManager, CeleryManager, Input, Output, html
import dash
from celery import Celery
import os
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)
print('using Redis caching')
else:
# Diskcache for non-production apps when developing locally
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'),
html.Div(
[
html.Div(
dcc.Link(
f"{page['name']} - {page['path']}", href=page["relative_path"]
)
)
for page in dash.page_registry.values()
]
),
dcc.Store(id='main-store'),
dash.page_container
])
if __name__ == '__main__':
app.run_server(debug=True)
pages/background_callback.py
import time
import dash
import pandas as pd
import json
import plotly.express as px
from dash import Output, Input, State, html, dcc, callback
dash.register_page(__name__,path='/')
layout = html.Div(
[
html.Div([html.P(id="paragraph_id", children=["Button not clicked"])]),
html.Button(id="button_id", children="Run Job!"),
]
)
@callback(
Output("paragraph_id", "children"),
Output('main-store','data'),
Input("button_id", "n_clicks"),
background=True,
prevent_initial_call=True
)
def update_clicks(n_clicks):
time.sleep(2.0)
return [f"Clicked {n_clicks} times"], [f"Clicked {n_clicks} times"]
DOKKU_SCALE
web=1
queue=1
requirements.txt
dash==2.7.0
gunicorn==20.0.4
pandas==1.1.4
diskcache
celery==5.2.7
redis==4.3.4
Procfile
web: gunicorn app:server --workers 4
queue: celery -A app:celery_app worker --loglevel=INFO --concurrency=2
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by running the supplied app.py with pages/background_callback.py and inspect the background callback registration and output handling around dcc.Store('main-store'). Done means the callback runs only after button_id is triggered, not on page load, with the shown Diskcache and Celery configurations.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python, redis
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100