Search code examples
javascriptasynchronousarchitecturewebsocketreal-time

What is a good practice to have an invariant ordering in a real-time commenting system?


Let's assume this use case:

Bob wants to comment a blog's post.
He is writing: "I'm the first to comment !".

A few milliseconds later, Alice put this comment: "I'm the second !".

Supposing that each posted comment is displayed to the other users by some kind of WebSockets, without refreshing the whole page.
And supposing that the comments list should be ordered by comment's date asc.

Bob should see this:

  • Bob: I'm the first
  • Alice: I'm the second

Now supposing the posting of comment is an asynchronous process, meaning as soon as a user clicks on "Send", the list is updated with its entry, not waiting for the server treatment :

What if the Bob's comment, despite being sent BEFORE Alice's one, is treated (stored) AFTER the Alice's one by the server?

The real display (but not effective on Bob's screen) would be:

  • Alice: I'm the second
  • Bob: I'm the first

but Bob would see:

  • Bob: I'm the first
  • Alice: I'm the second

=> It doesn't make sense...Alice typed on her keyboard right after Bob.

A simple refresh of the whole page would display:

  • Alice: I'm the second
  • Bob: I'm the first

Confusing for Bob !

This would not happen if the server process was synchronous, meaning that the list would be effectively displayed after the server commits the comment.
=> Bob would see Alice's comment appears before his, what is consistent.

How to deal with asynchronous in this case?


Solution

  • How would Alice know she is the second if Bob's comment didn't exists yet.

    For this particular example, if the order is not really relevant for the matter, I would put them in processing order or arrival order. That is the way it is done in majority of blogs and places where you can comment. Actually, it is usual to see the first two or three comments claiming to be the first :D

    Now, if order is really relevant, you can use a optimistic concurrency approach. Basically, each time you generate the page, you add a hash that identifies the state of the comments; when sending the comment you send that hash as well, and if the page didn't change between the user getting he page and inserting the comment, is all good, you generate the page again with the new comment and with a new hash; otherwise, it will return an "error" that will refresh the comments and warns the user that the page changed and he may need to review the page and current comments before writing the comment.

    UPDATE:

    IF you want a more reliable/async approach, you can use vector clocks. But it seems a little overkill for a chat :), probably showing them in arrival order is enough.