dash-table icon indicating copy to clipboard operation
dash-table copied to clipboard

PreventUpdate will block the previous callback

Open laoxu0212 opened this issue 4 years ago • 2 comments

Here is an example: If you click A, it may take a long long time to process it(like 30s). Inside of this 30s, B is clicked and triggered the same callback, let's say after some conditional judgement, it decides not to do anything.

But it will eventually raise PreventUpdate, and stop the A in the process as well(so I won't see "A is clicked").

import dash
import dash_html_components as html
from dash_table import DataTable
from dash.dependencies import Input, Output, State
from dash.exceptions import PreventUpdate

import time

app = dash.Dash(__name__)

app.layout = html.Div([
    DataTable(
        id="table",
        columns=[{'name': 'A', 'id': 'A'}],
        data=[{'A': 'unclicked'}]
    ),
    html.Button(
        'A',
        id='A',
    ),
    html.Button(
        'B',
        id='B'
    )
])


@app.callback(
    Output(component_id='table', component_property='data'),
    [Input(component_id='A', component_property='n_clicks'),
     Input(component_id='B', component_property='n_clicks')],
)
def update_table(a_clicked, b_clicked):
    if dash.callback_context.triggered[-1]['prop_id'] == 'A.n_clicks':
        print('A is clicked')
        time.sleep(30)
        return [{'A': 'A-clicked'}]
    if dash.callback_context.triggered[-1]['prop_id'] == 'B.n_clicks':
        print('B is clicked')
        # After checking some data shortly less than 30s, decide not to change anything.
    raise PreventUpdate


app.run_server(debug=False)

This problem wasn't seen in 1.1.1, but recently I upgraded my dash and start seeing that.

Is there any mechanism to let me still see "A-clicked" even B is clicked during that 30s sleep?

laoxu0212 avatar Jul 15 '21 21:07 laoxu0212

I am not sure if this is a bug or a feature. In any case, you should check out dash.no_update. Returning it for each output should avoid blocking the other callbacks.

canbooo avatar Jul 19 '21 12:07 canbooo

I am not sure if this is a bug or a feature. In any case, you should check out dash.no_update. Returning it for each output should avoid blocking the other callbacks.

Thanks for you help, actually I have already tried it before, it has the same problem.

def update_table(a_clicked, b_clicked):
    if dash.callback_context.triggered[-1]['prop_id'] == 'A.n_clicks':
        print('A is clicked')
        time.sleep(30)
        return [{'A': 'A-clicked'}]
    if dash.callback_context.triggered[-1]['prop_id'] == 'B.n_clicks':
        print('B is clicked')
        # After checking some data shortly less than 30s, decide not to change anything.
    return dash.no_update

So I'm just trying to find a way to get it like 1.1.1

laoxu0212 avatar Jul 19 '21 18:07 laoxu0212

Hi I'm facing this issue also as my callback gets triggered multiple times and as I allow the first one the following calls which raise PreventUpdate disable the one that I allowed. Is there any update on this issue?

BenMoveo avatar Mar 27 '23 14:03 BenMoveo

This repo is deprecated, dash-table has been incorporated into the main dash repo. For callbacks that takes longer than a couple seconds, we have background callbacks that offer better handling for this kind of situation.

T4rk1n avatar Mar 27 '23 14:03 T4rk1n