Denis Stephanov
Denis Stephanov

Reputation: 5281

Optimize async operation executed by rest for many users

in following code I have asynchronous method which is executed by rest by authenticated user. In this method I execute loop in which is checking periodically cache of new 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 = dataRepository.findByLastAndByUser(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 = dataRepository.findByLastAndByUser(dataId, userId);
    }

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

and executor bean:

@Bean
public Executor asyncExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setCorePoolSize(2);
    executor.setMaxPoolSize(2);
    executor.setQueueCapacity(500);
    executor.initialize();
    return executor;
}

I execute this checking in separate thread for every request because these data are different for each user.

I need to optimize this code for many users (about 10k active users). In current state it doesn't work well because where there is more requests, these requests are waiting for some new free thread, and every another request takes very long time (5 min instead of 100 sec for example).

Can you help me improve it? Thanks in advice.

Upvotes: 0

Views: 66

Answers (2)

Oreste Viron
Oreste Viron

Reputation: 3805

I don't fully understand what you want to do. But I think obviously it fill quickly your pool of thread.

I think you should try to use message broker or something like this.

Instead of trying to respond to request by waiting something new append, you should connect your clients with AMQP, WebSocket, Webhook... etc... On your server, when you detect new informations, you notify your clients.

So you don't need to occupy one thread by client.

Upvotes: 1

desoss
desoss

Reputation: 622

In case there are no other concurrent calls to the pollData method, it takes at most ~100s.

The parameter maxPoolSize defines the maximum number of thread that can run concurrently your @Asynch method.

So (number of users * execution time) / number of threads = 10K*100/2 = 500K[s].

I haven't completely understood the goal you want to reach with this method, but I suggest you to review the design of this functionality.

(For example take a look at spring cache, @evict,...)

(Notice that, in case you have multiple @async, you can bind the pool configuration with the @Asynch method by adding the name to the annotations @Bean("Pool1") and @Asynch("Pool1")).

Upvotes: 1

Related Questions