Yogesh_D
Yogesh_D

Reputation: 18809

Spring boot Limit number of concurrent invocations of a specific API in a controller

I have a sprint boot (v1.5.15) based Restful application that provides user based services, particularly login and get user details.

The login activity is slightly heavy where as the get user details api is pretty light weight.

I have a controller akin to this

@RestController
public class UserController{

    @PostMapping("/login")
    public LoginResponse userLogin(@RequestBody LoginRequest loginRequest){
        ...
    }

    @GetMapping("/users/{id}")
    public LoginResponse userIdGet(@PathVariable("id") String id){
        ...
    }

}

Is there any way I could limit the number of concurrent calls to the /login api. Basically I want to limit this to say x as the /users/{id} can handle in the same resources around 10x of that calls.

The application uses the embedded tomcat server and I know of server.tomcat.max-connections, server.tomcat.max-threads and server.tomcat.min-spare-threads however these restrict the calls at the application level rather than at the API.

Upvotes: 6

Views: 4098

Answers (1)

Christian Fries
Christian Fries

Reputation: 16952

There are solutions which limit the number of active connections, see e.g. https://dzone.com/articles/how-to-limit-number-of-concurrent-user-session-in .

However, afaik, such solutions are just rejecting further request.

If you do not like to reject request, you might limit the concurrent work done by using using an application wide fixed thread pool ExecutorService ( https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html#newFixedThreadPool(int) ) and submit your request body to that thread pool and imediatly call get on the returned Future.

So you can replace

@PostMapping("/api/xyzMethod")
public Response xyzMethod(@RequestBody Request request) {
    return handleXyzMethod(request); });
}

by

@PostMapping("/api/xyzMethod")
public Response xyzMethod(@RequestBody Request request) throws InterruptedException, ExecutionException {
    return xyzMethodExecutor.submit(() -> { return handleXyzMethod(request); }).get();
}

with some

private static ExecutorService xyzMethodExecutor = Executors.newFixedThreadPool(10);

A drawback is that the user might have to wait for the reply and / or that multiple request will fill the threads pool queue until the service becomes (too) unresponsive. So maybe you have to endow this solution with some kind of timeout on the FutureTasks or combine the two solution (that is also have a larger limit on the number of concurrent sessions).

Upvotes: 5

Related Questions