Open
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