Wrong callback_context in a long running callback if triggered while already running
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 24.4k
- Forks
- 2.3k
- Avg merge
- 2d 7h
- Merged PRs (30d)
- 13
Description
Describe your context
dash 1.12.0
dash-bootstrap-components 0.9.1
dash-core-components 1.10.0
dash-daq 0.4.0
dash-html-components 1.0.3
dash-renderer 1.4.1
dash-table 4.7.0
Describe the bug
I am using callback_context to determine which of my callback's inputs triggered the callback. Depending on which input it was, the callback may take quite some time. If during that time the callback is triggered by another input, the callback is executed with the same callback_context as for the first time it was called.
Example
Here is an example to demonstrate the problem:
import time
import dash
import dash_bootstrap_components as dbc
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
app = dash.Dash()
app.layout = dbc.Container([
html.Div(id='output'),
dbc.Button("First", id="first-button", className=""),
dbc.Button("Second", id="second-button", className=""),
])
@app.callback([Output('output', 'children')],
[Input('first-button', 'n_clicks'),
Input('second-button', 'n_clicks')])
def button_callback(first_button_n_clicks, second_button_n_clicks):
if not dash.callback_context.triggered:
return ['Initial callback']
retval = '{} button_callback triggered by {} = {}'.format(time.time(), dash.callback_context.triggered[0]['prop_id'],
dash.callback_context.inputs[dash.callback_context.triggered[0]['prop_id']])
print(retval)
time.sleep(5)
return [retval]
if __name__ == "__main__":
print(dash.__version__)
app.run_server(debug=True)
There are two buttons, both registered with the same callback. The callback sleeps for 5 seconds, then writes into a div which button was pressed.
If you press one button, then wait for the div to change, then press the other button, everything works as expected.
If you press one button and within 5 seconds press the other one, the callback is once again executed with the first callback context:
1589382775.3519113 button_callback triggered by first-button.n_clicks = 1
1589382776.8042998 button_callback triggered by first-button.n_clicks = 1 # <- I clicked second-button!
The return value of the first call to the callback also never makes it to the div. The div only ever shows what ever the last triggered callback outputs.
Expected behavior
I would expect each call to the callback to have the correct callback_context to enable it to make the proper decisions.
I would have also expected each returned value to be displayed on the page, regardless of whether there was another call to the callback while it was still doing it's work.
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 Dash example and tracing how callback_context is created for overlapping callback invocations. Focus on the callback_context entry point and verify that concurrent calls receive their own triggering input and that each completed return value is handled according to the expected behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 32/100