Dealing with the limited messagebus backlog


(David Taylor) #1

Continuing the discussion from Who's Online Plugin:

My plugin relies on receiving every message on a messagebus channel, in order, with no gaps.

As I understand it, if the client loses connection, it should receive all the messages it missed when connection is regained.

However… it seems the server only stores the last 100 messages, and so if the client misses more than 100 messages, it all goes horribly wrong.

One way I can think of dealing with this is for each client to check the message_id of each message and check it is 1 greater than the previous message it received. If not, get the missing information by some other method.

Is this problem faced in Discourse itself anywhere, and is there a more elegant solution?


(Jeff Atwood) #2

Maybe you need a webhook or some other event that’s triggered when users are “online” and “offline”?

The database definitely knows about user online events, without question; we write to the user table “last seen” when that happens. And we also know when users aren’t present as we only send email notifications when users aren’t online in the web browser by default.


(David Taylor) #3

I have no problem getting the “currently online” users on the server - that works fine. I added a hook to core so my plugin can run logic whenever “last seen” is updated :slight_smile:

The problem I have is keeping that server-side list in sync with the UI on the client. Rather than sending the entire list down the messagebus every time a user goes between “online” and “offline”, I only send the “delta”. However, this hits problems when some of those “deltas” are lost, hence the question.

I can definitely solve the problem, I’m just wondering whether there’s a nicer way


(Jeff Atwood) #4

That seems like a premature optimization, unless there are 50+ users online surely sending down a simple list is … simpler? Maybe the more complex behavior is only needed for large lists?


(Sam Saffron) #5

Easy, add a second channel that sends full participant list every n minutes, or just change your existing message also to include the full list


(Sam Saffron) #6

Or, if after you publish a message the id is mod 50, send the refresh


(David Taylor) #7

I like that idea - but is there any way for me to programmatically find out the ‘maximum size’ of the backlog, just in case it changes in future? It looks like it’s set to 100, but I can’t find where that number is set in the discourse codebase.


(Sam Saffron) #8

It should be exposed via message bus


(Matt Palmer) #9

Side commentary: you need to redesign your plugin to remove that requirement. What you appear to be relying on is akin to saying “my car relies on this perpetual motion machine” – it’s not physically possible. There’s not even any theoretical way to guarantee exactly-once processing of a message, let alone being able to rely on it in any real-world situation (storage limitations, bugs, etc).


(David Taylor) #10

I should probably clarify that it currently relies on receiving every message “after the initial page load”, so no different from how many things on Discourse work (e.g. notifications). If a user misses 100 notifications (e.g. by leaving their computer on “sleep” with Discourse open), then it would have exactly the same issue.

My plugin just hits that edge case more frequently, so I do need to make some changes, hence the thread.

Thanks for all the suggestions everyone :slight_smile: