dash icon indicating copy to clipboard operation
dash copied to clipboard

[BUG] Dependent callbacks are not waited and executed in order

Open fraghag opened this issue 4 years ago • 12 comments

Describe your context I have a problem with chained callbacks where the last callback is called twice from one UI change. In the documentation I found this https://dash.plotly.com/basic-callbacks where it states under “Dash App With Chained Callbacks” that:

The final callback displays the selected value of each component. If you change the value of the countries RadioItems component, Dash will wait until the value of the cities component is updated before calling the final callback. This prevents your callbacks from being called with inconsistent state like with "America" and "Montréal" .

But when changing between America and Canada in the example on this page I can see that it first updates the text with the country and then the city. So when changing from America to Canada I can see “New York City is a city in Canada” very briefly which according to the documentation should not happen. I also ran this example locally with debugging and verified that the callback updating the text is run twice whenever I change the country.

dash                               1.18.0
dash-bootstrap-components          0.10.7
dash-core-components               1.14.0
dash-html-components               1.1.1
dash-renderer                      1.8.3
dash-ri-components                 2.1.0
dash-table                         4.11.1

Describe the bug Callback A and callback B has resource A as a dependency, callback B is also dependent on the output of callback A. When changing resource A, then callback A can be run before callback B is finished, and then runs again when callback A finishes since callback A updates another of callback B's input.

image

Expected behavior

When chaining callbacks, callback B should wait for callback A to finish, if callback B is dependent on the output of callback A.

fraghag avatar Jan 07 '21 11:01 fraghag

Thanks @fraghag - I see it too and you're absolutely right that this is a bug. We'll have to poke around and see if this is a regression or simply a case that for some reason we've never handled correctly.

alexcjohnson avatar Jan 07 '21 13:01 alexcjohnson

I have the same problem with an app that I am developing. I have two chained callbacks, one change the values of several sliders (10) together and the other one implements a function on these sliders values. The problem is that I need to evaluate the function when all the slider values have changed but I found that it fires up ten times, once every time a single slider value is updated. This causes a problem since it fires up with only partially changed values and raises errors.

francescobodria avatar Mar 12 '21 09:03 francescobodria

Hey everyone, I have started working on this issue.

First of all, can someone confirm by looking at the following screen recording if I am reproducing the issue correctly.

https://www.loom.com/share/daaf5d30f76e455aa46705829fdd739d

@alexcjohnson @Marc-Andre-Rivet @fraghag

eff-kay avatar May 06 '21 15:05 eff-kay

Bringing the discussion from slack in here.

Following is the graph created for the chained callbacks app, where (CoV = CountriesValue, CiV= CitiesValue, CiO = CitiesOptions, DiC = DisplayChildren, cb = callback ). I have left out CountriesOptions (CoO) because that is not relevant here.

Screen Shot 2021-05-06 at 10 40 35 AM

Following are the steps performed, when CountriesValue is updated.

  1. Call the CitiesOptions callback, and DisplayChildren callback.
  2. CitiesOptions calls the CitiesValue callback.
  3. CitiesValue calls the DisplayChildren again.

DisplayChildren is called twice, the first one renders a stale value. But eventually, the correct value is displayed.

eff-kay avatar May 06 '21 16:05 eff-kay

@alexcjohnson commented the following

Ah OK, I see what you’re saying Faizan. I think your interpretation is correct, but yeah we may need to specifically handle several cases differently:

  • if a callback outputs one prop that then internally to a component changes another prop (ie changing options causes value to be changed)

    • not really sure there can be a general solution for that… at the renderer level we don’t know what internal linkages a component has.
  • if a callback outputs children, and inside one of those components there is another callback output

    • we could look at the paths involved and have the parent callback block the child callback. This is tricky though because there can be cases we use this kind of callback intentionally to generate circularity (that the user then needs to carefully manage to avoid infinite loops) and we wouldn’t want that case to completely lock up.

eff-kay avatar May 06 '21 16:05 eff-kay

The fix that I have right now is the second one, i.e. CountriesValue upon update, initiates two callbacks (CitiesOptions, and DisplayValue).

I traverse the CitiesOptions callback path to see if it calls DisplayValue at any point. If yes, then discard DisplayValue. from the children of CountriesValue

I don't think the first one is the cause of the issue here, if I am understanding it correctly. The issue will only occur if it's the second case. i.e. a callback is called twice, and one of them returns a stale value because it's called too soon.

eff-kay avatar May 06 '21 16:05 eff-kay

In summary the two options that @wbrgss mentioned seem to be the solutions here.

  1. Prune the extraneous callback, which is what I am doing right now.
  2. Block/hold for dependencies, this will require some sort of dependency resolution.

eff-kay avatar May 06 '21 16:05 eff-kay

same problem

isCopyman avatar Sep 21 '21 09:09 isCopyman

is there any update on this?

cdolfi avatar May 05 '22 23:05 cdolfi

cc @alexcjohnson.

eff-kay avatar May 06 '22 00:05 eff-kay

Bumping again, I’m encountering this bug so very interested in getting a fix

groegercesg avatar Jul 06 '22 10:07 groegercesg

Hi @groegercesg, this is in the queue, the fix has been finalized, just needs some final testing and rebasing before it can be merged.

eff-kay avatar Jul 06 '22 18:07 eff-kay

Hi @eff-kay! Any news on this bug fix?

fraghag avatar Nov 07 '22 16:11 fraghag

@fraghag sorry we got busy with the DE5 release. Now that the release is done, I can schedule some time to get this through. Ideally in the next few weeks.

eff-kay avatar Nov 07 '22 18:11 eff-kay