I might have stepped over a callback chaining issue.
I’ve closely followed the example written here: Pattern for avoiding circular dependency in Dash callbacks - #2 by ebosi
Expected:
When running this app below, upon clicking the button you should see a string below the button “got start_signal.children” and after 3s this should change to “got end_signal.children”.
What happens:
However, upon clicking the button nothing happens and only after 3s you see either of the two messages depending on the server config (e.g. flask/gunicorn).
So it seems the callbacks are not executed in parallel but rather chained, giving the long running process priority (for whatever reason).
Tried with:
kubuntu 20.04
Python 3.7, 3.8
dash 1.6, 1.9, 1.10, 1.12
Flask, waitress, gunicorn (multiple workers)
firefox, chrome
changed the order of object, functions and arguments in the code (no effect)
Verdict:
I would be happy, if the callbacks (at least for one user session) don’t run in parallel but are rather chained but would need a way to control execution order instead. Is this a bug or intended behavior?
import dash
from dash.dependencies import Input, Output
import dash_html_components as html
import time
app = dash.Dash(__name__)
app.layout = html.Div([
html.Button("start job (3s)", id="start"),
html.Div("Not run", id="div"),
html.Div(id="start_signal", hidden=True),
html.Div(id="end_signal", hidden=True),
])
server = app.server
@app.callback(Output("start_signal", "children"),
[Input("start", "n_clicks")])
def start(_button):
return True
@app.callback(Output("div", "children"),
[Input("start_signal", "children"), Input("end_signal", "children")])
def show(_start_signal, _end_signal):
prop = dash.callback_context.triggered[0]['prop_id']
return f"got {prop}"
@app.callback(Output("end_signal", "children"),
[Input("start_signal", "children")])
def job(_signal):
time.sleep(3)
return True
if __name__ == "__main__":
app.run_server(debug=True, threaded=True)