Dash background callback cancel does not work

Hi guys. I am running dash 2.9.3 and I cannot seem to make the background callbacks to cancel. The callbacks themselves are triggered but whenever I try to cancel, nothing happens.

def content():
    return html.Div(
        [
            html.Div(
                [
                    html.P(id="paragraph_id", children=["Button not clicked"]),
                    html.Progress(id="progress_bar"),
                    html.P(id="process_id", children=["Process id:"]),
                ]
            ),
            dash_bootstrap_components.Button(id="button_id", children="Run Job!"),
            dash_bootstrap_components.Button(id="cancel_button_id", children="Cancel Running Job!"),
        ]
    )

and this is my callback definition:

@dashapp.callback(
        output=Output("paragraph_id", "children"),
        inputs=Input("button_id", "n_clicks"),
        cancel=[Input("cancel_button_id", "n_clicks")],
        running=[(Output("button_id", "disabled"), True, False),
            (Output("cancel_button_id", "disabled"), False, True)],
        background=True
    )
    def callback(n_clicks):
        total = 10
        for i in range(total):
            time.sleep(0.5)
        return [f"Clicked {n_clicks} times"]

The example I am using is the same as in the documentation, so I assume the error is somewhere else.
My dashapp runs in a flask server and is defined as such:

dashapp = dash.Dash(
        app.import_name,
        server=app,
        url_base_pathname=f'/{base_pathname}/' if base_pathname else '/',
        meta_tags=[meta_viewport],
        suppress_callback_exceptions=True,
        serve_locally=debug,
        compress=True,
        background_callback_manager=background_callback_manager,
        assets_folder=f'{os.getcwd()}/dashboard/static'
    )
return dashapp

Any clues what might be causing the issue?

1 Like

I have the same issue. I cannot force the callback to cancel. I even verified with a test callback that my button is indeed clicked:

@callback(
    [
        Output("#someDiv", "children"), # random div as output
    ],
    [
        Input("cancel_button_id", "n_clicks")
    ],
    prevent_initial_call=True,
)
def cancel(*_):
    print("cancel clicked")
    return dash.no_update

I get the message “cancel clicked” but it does not trigger the callback described above to cancel.

Hey @AurelianCtin welcome to the forums.

Your callback is actually not a background callback. You have to set background=True and add provide a component to the cancel parameter.

@callback(
    Output(...),
    Input(...),
    cancel=[Input(...)],
    background=True
)

see also

1 Like

Alright, I think I found the root cause of the problem.
I am developing my app on a windows machine.
Unfortunately Celery no longer supports Windows, what stopped working is the prefork pool, which is Celery’s default pool.

To mitigate this when I am starting my Celery process I use -pool=solo:

celery -A app.celery_app  worker --loglevel=INFO --pool=solo

From what I was able to find info on (python - How to revoke the task while running - Stack Overflow), the issue with using a different pool is that it won’t accept task cancellation , like prefork does.

In the end , I think Windows is the issue for me.

1 Like