Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When multiple users are viewing a record and 1 person updates the record, how to notify other the record is updated?

In my Project Management app I want to solve the issue of multiple users viewing the same Task record and 1 or more of them updating some of the Tasks Data while the others are viewing it.


Here is a scenario...

User #1 views Task #1 and User #2 views Task #1

Now User #2 updates the Task #1 Description

User #1 is now viewing the Task record but his view shows a different out-dated Description since User #2 had just updated it! Even worse he may want to edit the description himself which would completely over-write User #2's Description update.


That is 1 example of the issue. Just add more users and the issue multiplies!

Ideally I would use something like Sockets or a service like Pusher.com to update the data for all users as soon as an update by any user is made. However this project is going to be on hundreds of servers and has limited capabilities as far as server requirements so sockets and even a service like Pusher are out of the question!

Another idea for a solution is based on what Twitter does. If you view a persons Twitter page and they make a new post while you have there page loaded. It will show a notification message DIV to tell you there are X number of new posts and give you a link to click to reload the stream of posts with the latest posts.

enter image description here

I believe a similar approach could work for my project. If a user makes an update to any Task data while other users are viewing that Task record. It would show a Notification message on the Task modal window telling the user that the Task data has been updated and that they should reload the Task.

To make this work I know there will need to be some AJAX request made at some interval.

That AJAX request would then need to compare the timestamp of the last update made on the Task record and compare it with the time the user viewing the Task record started viewing it or since they last reloaded the task.

I feel like my logic is missing a piece of the puzzle though? Is this all correct or am I missing something?

Can someone explain how I can do this or tell me if what I have in mind is right?

I know that in short I simply need to determine if the Task last modified Timestamp is AFTER the other user started viewing the Task. At some point though I feel the users time should be updated too?

UPDATE

I completely forgot that Stack Overflow does this exact task on questions and answers! When you view a page on SO and a Answer is updated it will show a notification message telling you to reload the answer and provide a link to reload it. That is what I want to do!

StackOverflow uses Web Sockets to do this but in my app which is a plugin to be used on many different server configurations, I cannot use Sockets. I am trying to achieve similar result with AJAX. Even if it's an AJAX request made every 30 seconds to get the task modified Time and compare it to another to determine if user should reload task data would work in my case

enter image description here

like image 278
JasonDavis Avatar asked Dec 18 '15 01:12

JasonDavis


2 Answers

Your question is too broad, but you are basically describing a Pub/Sub.

Idea

Whenever a user enters your site, he gets a token to identify them.

If he accesses a task, he subscribes to that task, which means that any modification on it would be alerted to him.

He polls the server to check if there is any alert to him.

Implementation

Regarding implementation, you can set-up a list with each user's subscriptions. Using your example:

User1 subscribes to (Task1, Task2)

User2 subscribes to (Task1)

With each subscription, you keep some value that represents the last state the user has about that topic (e.g, the last modification timestamp).

The user polls your application every n seconds. Whenever the request reaches your application, you check the user's subscriptions, and check if the timestamp has changed (if they have the latest). If so, you update the last state that the user has and retrieves him the new values for the tasks that changed.

Things to consider

This list of subscriptions will be constantly accessed, so becareful where you are going to store it. If in memory, consider that you will need to share it across the different instances (if you are load balancing). You can use Redis, or something like that.

You do not need to go to your database everytime you need to retrieve data. If someone is subscribing to it, keep it on a cache.

like image 200
Walter Macambira Avatar answered Oct 03 '22 20:10

Walter Macambira


The concept and idea is fairly trivial, and the implementation shouldn't be any more difficult. You need a Last Updated timestamp for each task as you say, as well as a Last Update timestamp on the client if you go with the described approach. Generally, when a User is viewing a Task, you'd want to (on the client side, Javascript):

  1. Query the server for the Last Updated timestamp of the Task being viewed with AJAX.
  2. If the Last Updated timestamp of the Task being viewed is greater (newer) than the Last Update timestamp on the client goto step 5.
  3. Wait (asynchronously) n seconds.
  4. Goto step 1.
  5. Notify User that the Task being viewed has been updated.
  6. End (since it is already known to the client that the Task has been updated, there is no need to keep polling whether it's been updated or not).

One approach could be simply creating an asynchronous interval using setInterval() that would be cleared once it has been determined an update occurred, and the user is shown a message afterwards.

var lastUpdate = Date.now();
var intervalDuration = 30000; // 30 seconds
var interval = setInterval(function () {
    var xhr = new XMLHttpRequest();
    ...
    xhr.onload = function () {
        if (...) { // if the Task's Last Updated timestamp is newer than lastUpdate
            clearInterval(interval);
            // show message to user that the Task has been updated
        }
    };
}, intervalDuration);

I can imagine in a significantly massive system this approach could be easily inadequate, but for non-enterprise grade solutions or for follow-up UI improvements this can be a quick, cheap, and spectacular solution.

Of course there are potentially more robust and flexible alternatives to this: long-polling or websockets.

like image 35
John Weisz Avatar answered Oct 03 '22 18:10

John Weisz