Dash callbacks missing data on fast updates < 100ms

I have noticed something in my dash application where callbacks are not being fired if subsequent callbacks are less than 100ms later. It seems like the last callback is always being fired. I have noticed this in 2 scenarios

  1. I have data being streamed to a custom websocket component. The component then uses setProps to “broadcast” this message change to an Input of a client side callback. I see the incoming messages are received by the custom component, but the callback that receives the message to an Input skips the first message (in an example where 2 messages are coming within 100ms of each other)

  2. I have an interval that updates a slider. If the interval is 20ms the slider value on gets updated when the interval is stopped. If i set the interval value to 100ms then it updates on every tick.

I have “solved” this issue by throttling the update frequency of the websocket setProps, but I cannot expect to do this for all other scenarios where the callbacks are fired within 100ms.

Has anyone encountered anything like this or knows of a workaround?

Hello @dales,

Yes, I have noticed this. If you look at your browses network tab you can see what’s happening. Depending on the process of data manipulation on the server side, you start running into a bottleneck of requests.

On top of that, each update is normally blocking and not asynchronous.

Workaround for fast callbacks is to do client side. You just need to figure out how to send the new info to the client somehow for it to use it.

My issue is client side only, if i look at my network tab i can see all the websocket traffic coming in, and if I add a debug log in my custom websocket component from devtools I can see the traffic ALL arrives. The problem is the callbacks are missing the changes. My callbacks in this case are all clientside already :pensive:

1 Like

Do you have any if statements that might be keeping it from performing as expected?

I dont think this is the problem, if i add sleeps on my websocket server sending the data then it performs correctly. And if i increase the interval to 100 instead of 20 then it works as expected too

dcc.Interval(id="sample-progress-interval", interval=100, disabled=True),

[Update: Ignore interval issue - solved moving all of the code to clientside callback]

@dales,

Are you using the websocket to send the data and then the n_intervals to pick up that data from the websocket? Is it possible to trigger the clientside callback from the websocket being received?

Add a console.log to the clientside callback where the data is supposed to be referenced. And also, if possible, add a console.log to the websocket process to display the new data.

No, there are 2 separate cases here where i have noticed this.

  1. The websocket case with fast data
  2. The interval case where interval time is 20ms

Regarding the websocket, if i add a console.log inside my websocket component, I see all of the data. I then do setProps on the data and expose that property (message). I have another clientside callback running listening to the message property. If i do a console.log inside of this i only see the second websocket message, the first doesnt appear at all

Just an update, ignore the part about the interval, I had a part that I was sure was client side but was server side. Changing it to client side solved that problem. But the issue of the websocket data updating fast is still an issue

1 Like

I’ve noticed with adding listeners to the dash elements, that sometimes things wont work but every other time.

My workaround for this is to unbind and then reapply, triggered with the dash-update-components to reapply.

It sounds like you may be encountering something similar.

What happens if you apply the new data twice to the prop?

you mean calling setProps twice?

componentDidMount() {
    const { setProps, url } = this.props;
    this.setProps = setProps;
    ....
}

And later when in “this.ws.onmessage” I do this

this.setProps({msg: data});
```
1 Like

I think I am experiencing this exact same issue. Sending websocket messages, then doing clientside updates based on those messages. I can see all of the websocket messages arrive, but some of the clientside callbacks seem to be skipped.

Anyone know of any better solutions than just throttling websocket messages from the server side?

Depending on your usecase, one option could be to collect the messages in chunks before invoking the callback.

1 Like

@Emil Thanks for your very quick response!

When you say collect the messages in chunks before invoking the callback, do you mean on the serverside or clientside?

If you mean clientside, do you have a recommendation on roughly how to go about this?
At the moment I have a clientside callback that looks like this:

clientside_callback(
    f"""
    function(message, current_content) {{
        if(message) {{
            const message_data = JSON.parse(message.data);
            const message_type = message_data.response_type;
            const message_content = message_data.message;
            if (message_type === 'START') {{ 
                return message_content;
            }} else if(message_type === 'UPDATE') {{
                return current_content + message_content;
            }} else {{
                throw window.dash_clientside.PreventUpdate;
            }}
        }}
    }}
    """,
    Output('markdown', "children"),
    Input('websocket', "message"),
    State('markdown', "children"),
    prevent_initial_call=True,
)

If I were to try and collect the message chunks on the clientside first, I think I would end up just doing something very similar with a dcc.Store component rather than a dcc.Markdown, but then I expect I’d have the same issue (although I may be wrong).