Denis Stephanov
Denis Stephanov

Reputation: 5231

Hold thread in spring rest request for long-polling

As I wrote in title we need in project notify or execute method of some thread by another. This implementation is part of long polling. In following text describe and show my implementation.

So requirements are that:
UserX send request from client to server (poll action) immediately when he got response from previous. In service is executed spring async method where thread immediately check cache if there are some new data in database. I know that cache is usually used for methods where for specific input is expected specific output. This is not that case, because I use cache to reduce database calls and output of my method is always different. So cache help me store notification if I should check database or not. This checking is running in while loop which end when thread find notification to read database in cache or time expired.

Assume that UserX thread (poll action) is currently in while loop and checking cache.

In that moment UserY (push action) send some data to server, data are stored in database in separated thread, and also in cache is stored userId of recipient.

So when UserX is checking cache he found id of recipient (id of recipient == his id in this case), and then break loop and fetch these data.

So in my implementation I use google guava cache which provide manually write.

private static Cache<Long, Long> cache = CacheBuilder.newBuilder()
        .maximumSize(100)
        .expireAfterWrite(5, TimeUnit.MINUTES)
        .build();

In create method I store id of user which should read these data.

public void create(Data data) {
    dataRepository.save(data);
    cache.save(data.getRecipient(), null);
    System.out.println("SAVED " + userId + " in " + Thread.currentThread().getName());
}

and here is method of polling data:

@Async
public CompletableFuture<List<Data>> pollData(Long previousMessageId, Long userId) throws InterruptedException {
    // check db at first, if there are new data no need go to loop and waiting
    List<Data> data = findRecent(dataId, userId));

    data not found so jump to loop for some time
    if (data.size() == 0) {
        short c = 0;
        while (c < 100) {

            // check if some new data added or not, if yes break loop
            if (cache.getIfPresent(userId) != null) {
                break;
            }
            c++;
            Thread.sleep(1000);
            System.out.println("SEQUENCE:  " + c + " in " +  Thread.currentThread().getName());
        }

        // check database on the end of loop or after break from loop
        data = findRecent(dataId, userId);
    }

    // clear data for that recipient and return result
    cache.clear(userId);
    return CompletableFuture.completedFuture(data);
}

After User X got response he send poll request again and whole process is repeated.

Can you tell me if is this application design for long polling in java (spring) is correct or exists some better way? Key point is that when user call poll request, this request should be holded for new data for some time and not response immediately. This solution which I show above works, but question is if it will be works also for many users (1000+). I worry about it because of pausing threads which should make slower another requests when no threads will be available in pool. Thanks in advice for your effort.

Upvotes: 0

Views: 3221

Answers (1)

Rahul
Rahul

Reputation: 677

Check Web Sockets. Spring supports it from version 4 on wards. It doesn't require client to initiate a polling, instead server pushes the data to client in real time.

Check the below:

https://spring.io/guides/gs/messaging-stomp-websocket/

http://www.baeldung.com/websockets-spring

Note - web sockets open a persistent connection between client and server and thus may result in more resource usage in case of large number of users. So, if you are not looking for real time updates and is fine with some delay then polling might be a better approach. Also, not all browsers support web sockets.

Web Sockets vs Interval Polling

Longpolling vs Websockets

In what situations would AJAX long/short polling be preferred over HTML5 WebSockets?

In your current approach, if you are having a concern with large number of threads running on server for multiple users then you can trigger the polling from front-end every time instead. This way only short lived request threads will be triggered from UI looking for any update in the cache. If there is an update, another call can be made to retrieve the data. However don't hit the server every other second as you are doing otherwise you will have high CPU utilization and user request threads may also suffer. You should do some optimization on your timing.

Instead of hitting the cache after a delay of 1 sec for 100 times, you can apply an intelligent algorithm by analyzing the pattern of cache/DB update over a period of time.

By knowing the pattern, you can trigger the polling in an exponential back off manner to hit the cache when the update is most likely expected. This way you will be hitting the cache less frequently and more accurately.

Upvotes: 1

Related Questions