Black Lives Matter. Please consider donating to Black Girls Code today.

How to stop a callback

Hi,

i am developing my first dash app. One of the callbacks runs an optimization. My problem is sometimes takes the optimization to long and i want to stop it. Maybe with a button, but I can not change the button state inside of a callback. Maybe it is a better solution for this.

Thanks

Rafael

Hi @robraun, welcome to the forum! You can add a “stop” button as input to your long callback, and when it’s get clicked it will fire the callback again without waiting for the first one to terminate. I’m not sure your long computation would be stopped but at least you would have interactivity again. See the example below which is using the dash context to know which button was clicked

import dash
import dash_html_components as html
from dash.dependencies import Input, Output
from time import sleep

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

app.layout = html.Div([
    html.Div(id='content'),
    html.Button('Button', id='button1'),
    html.Button('Stop', id='stop'),
])


@app.callback(
    Output('content', 'children'),
    [Input('button1', 'n_clicks'),
     Input('stop', 'n_clicks')
        ])
def long_callback(click1, click2):
    ctx = dash.callback_context

    if not ctx.triggered:
        button_id = 'No clicks yet'
    else:
        button_id = ctx.triggered[0]['prop_id'].split('.')[0]

    if button_id == 'button1':
        sleep(5)
        return "completed callback"
    elif button_id == 'stop':
        return "stopped callback"


if __name__ == '__main__':
    app.run_server(debug=True)

So I checked and this method does not stop the calculation done by the callback, it just stops the app from updating. Maybe a better solution can be found.

Hi Emmanuelle,

thanks for your help. I tried in this way the first time, but i can not stop the python calculation. The buttons state do not change inside of the callback. I am trying to separate the callback in smaller callbacks to have a better interaction, but it is difficult. Maybe it is anothe way to stop python procesees without to stop the complete app.

Regards

Rafael

To achieve this kind of behavior, you should launch the calculation asynchronously (e.g. using celery or dask) so that the app remains interactive.

Upon calculation completion, you can then insert the result in a server cache (e.g. redis) or you could simply write a file to disk. Using an interval component you can pull for updates (check the redis cache, or if the result file has been written to disk).

Similarly, via the button click, you can signal the async calculation to stop via a redis cache. How this is done exactly will depend on your specific implementation; a very simple solution would be to store a flag in the redis cache, which is checked in the async calculation once per second or so.

Thanks Emil, your answer is exact what I need to do. Now i have to do it… Maybe do you have a simple example? I am beginning now with tutorials to resolve my problem.

Rafael