-
-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[BUG] background callback with MATCH is cancelled by future callbacks with different component ids #2681
Comments
If you are updating the same output with 2 different inputs and the second asynchronous call finishes before the first one. It updates the component. Then the first one finishes and updates the component, undoing the changes from the second input. Is that the behavior we want? |
I'm running into the same issue. The desired functionality is that all Outputs are updated the same way as if the callbacks were normal callbacks, not background callbacks. @dwmorris11 each callback is updating a separate output. In the MWE provided there are no two callbacks changing the same output, because all the ID dictionaries for both buttons and paragraphs are different. |
I am also having what I think is the same issue. Here's a different minimal repro: import time
from uuid import uuid4
from dash import MATCH, Dash, DiskcacheManager, Input, Output, State, html
app = Dash(__name__, background_callback_manager=DiskcacheManager())
N_JOBS_TO_ADD = 50
div = html.Div(children=[])
button = html.Button(children=f"Add {N_JOBS_TO_ADD} jobs")
@app.callback(
Output(div, "children"),
State(div, "children"),
Input(button, "n_clicks"),
prevent_initial_call=True,
)
def click_button(children, n_clicks):
print(f"click_button({len(children)=}, {n_clicks=})")
children.extend(
[
html.Div(["In Progress..."], id={"type": "test", "value": str(uuid4())})
for _ in range(N_JOBS_TO_ADD)
]
)
return children
@app.callback(
Output({"type": "test", "value": MATCH}, "children"),
Input({"type": "test", "value": MATCH}, "id"),
background=True,
)
def update_progress(id):
print(f"update_progress({id=})")
time.sleep(1)
return ["Done"]
app.layout = html.Div([button, div])
app.run(port=8051, debug=True) When clicking the "Add 50 Jobs" button I expect the app to create 50 divs with the text "In Progress...", kick off 50 background callbacks which take a second to run, and should replace the text in each of the divs with "Done". Instead, only a few of them update with "Done" and the rest stay at "In Progress...". I'm not sure if the callbacks are "cancelled", but nevertheless most of the matched output components don't update. Additionally, if I try to "intercept" between this callback and the html component update, for e.g. by outputting to an intermediary store, then adding a new callback using the store to update the component, that intercepting callback similarly will only be called a few times---in the same way that only a few divs are updated. |
Alkasm's example illustrates the problem perfectly. The whole behavior switches when setting "background" between True and False. I also want to add that in my app I am using a Celery background manager, while the example above uses Diskcache manager, so it is probably unrelated to a specific manager. I also noticed that almost always six calls complete while the rest stalls (the callbacks continue to run but the result returned seems to be an empty base Object), so maybe that's exactly the first round of parallel processes being completed and from there on the rest is affected. |
Describe your context
Describe the bug
If a background callback using pattern matching with
MATCH
is triggered twice by two different objects (and therefore different values forMATCH
), the first callback will be cancelled.This only applies to background callbacks. "Normal" callbacks work fine.
Expected behavior
Both callbacks should finish execution and return their outputs, just like non-background callbacks. (At least if their IDs are different)
MWE
Here's a small example to reproduce the problem:
If you click on multiple buttons (within 3 seconds after the last click), the previous execution of the callback will be canceled and only the id of the last button will be shown.
Sample output:
The text was updated successfully, but these errors were encountered: