Behavior when new event is triggered before previous callback is done

Apologies for another post without a reproducible example. But unfortunately I think this only becomes relevant for more complex apps. It seems like I often see some some strange behavior when I do something in the UI before all the previous callbacks have finished.

The layout of app is this: I have a master dropdown at the top. Then I have five tabs, each with a div with a table and a graph, that depend on the master dropdown (showing different info). The graphs depend on both the dropdown and the rows selected in the table. Changing the master dropdown updates all the tables/graphs. The divs change visible/invisible depending on the tab selection.

It takes a few seconds for all the graphs/tables to update. It seems that often (again, unfortunately can’t get this to be reproducible) I can get something screwy to happen if I change the tab before all the tables/graphs have updated. Sometimes the content just seems to disappear completely (I get whitespace instead of the div with the graph/table under certain tabs, while other tabs work fine). Sometimes I get graphs that are supposed to be under different tabs both showing up under the same tab.

Any ideas for something I could be doing wrong?

Thanks for reporting! A reproducable example would be really helpful here, even with something like time.sleep(5) inside the callbacks. Screenshots and/or a video/GIF would also be really helpful.

It doesn’t sound like you are doing anything wrong, it sounds like Dash could be dealing with this behaviour more gracefully, but I can’t say for certain without seeing an example unfortunately.

Are you seeing this behaviour with multiple workers (e.g. with gunicorn) or just with the single worker app.run_server?

In the case when multiple long-running callbacks are fired and executed in parallel, there is a chance that the callbacks could return in a different order than they were executed in. For example:

1 - Callback Fired - Takes 5 seconds
2 - Callback Fired - Takes 3 seconds

In this case, the first callback will finish after the second callback. In Dash’s front-end, we keep track of the order of these callbacks and we reject the results of older callbacks if newer results have already returned. In this case, we would reject the results of 1 - Callback that would return 2 seconds after 2 - Callback.
Perhaps the wacky behaviour that you are seeing is somehow related to this logic. We have an integration test for this behaviour here: dash-renderer/tests/test_render.py at 9992d73303492671d9619c161b9184d35f43faf6 · plotly/dash-renderer · GitHub, perhaps you can use that simple example as a basis for a reproducable example.

Thanks again for reporting!

Thanks for the info @chriddyp that’s helpful in trying to construct an example.

This is all on one worker. Windows environment, so unfortunately I don’t have access to gunicorn.

In case it’s an option for you, there is the Linux Subsystem for Windows 10 which only today I happened to confirm that you can run Dash apps using gunicorn on.

I have a suspicion that the weird behavior I was seeing was due to one of the callbacks returning None in particular cases.

Fixes this case as far as I can tell – of course would be great for development if there was a clearer error displayed in the console in these types of cases.

1 Like

You can avoid callbacks getting None in many instances by ensuring that components have the relevant property initialized to something. like value='' for the Input component. But I agree, it’s still easy to get stung by this. There’s the Location component for example, where the first run of the callback targeting the url property returns None, which is currently unavoidable.