plotly / plotly/dash

Long callback function executed without being triggered in Dash Pages with Background callback

Open
#2,369 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug dash-callbacks P3
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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.