Reputation: 4071
I am relatively new to Spring Boot and started with the very simple example from their getting started site, which is (on the controller side):
@RestController
public class HelloController {
@RequestMapping("/")
public String index() {
return "Greetings from Spring Boot!";
}
}
What I want now, is that multiple (potentially long running) requests of the same controller can be served in parallel.
Since I already learned that a
Update: My bad: I thought it was related to the fact that the controller was a singleton. But true: Why should it not be able to run in parallel then?@RestController
will be instantiated as singleton, it is clear for me, that multiple requests (which are handled by the same method) will be processed sequentially.
So I changed the example from above as follows so that a new instance of the controller is created on every request and with some means of inspecting what's actually happening:
@RestController
@Scope(value = "request")
public class HelloController {
private static AtomicInteger count = new AtomicInteger(0);
public HelloController() {
count.incrementAndGet();
}
@PostConstruct
public void init() {
System.out.println("start request " + count);
}
@PreDestroy
public void onDestroy() {
System.out.println("end request " + count);
}
@RequestMapping("/")
public String index() throws InterruptedException {
LocalDateTime now = LocalDateTime.now();
TimeUnit.SECONDS.sleep(15);
System.out.println(now);
return "Greetings from Spring Boot! " + now + " " + count.get();
}
}
Now I would expect to see that the requests are handled in parallel in about 15 seconds, but in fact I can only see that it is obviously processed sequentially and that it takes 30 seconds (on stdout):
start request 1
2017-02-11T14:19:47.429
end request 1
start request 2
2017-02-11T14:20:02.467
end request 2
So my question is: How can I achieve that such requests are processed in parallel since it is obviously not sufficient to create an instance for each request?
Little remark: I already tried using the @Asnync
annotation in combination with @EnableAsync
for the application class, but this seems to be a "fire and forget" such that I cannot get a response to show on the client side.
Several entries here on stackoverflow (eg. this and this) were interesting, but did not answer my question either, neither did this tutorial about asynchronous methods.
Update: Since several people pointed out that the issue may be related to the way I tested, I tried to run it with a different browser. Interestingly enough I experienced the same issues on Chrome as well as on Firefox. But when doing one request from each, it showed the expected behavior (serving the requests in parallel) – so I was fooled by the browers ...
Upvotes: 4
Views: 20075
Reputation: 34920
You wrote:
Since I already learned that a @RestController will be instantiated as singleton, it is clear for me, that multiple requests (which are handled by the same method) will be processed sequentially.
"...will be processed sequentially" - this is false statement. I even have no idea on what basis it was made. Until you make method synchronized (or will use other lock technics), it will be accessible by multiple threads simultaneously.
In second case you've just configured it to create new instance for each request. I have only one idea explaining why do you receive sequential results in debugger: you perform this requests from browser sequentially as well.
If you want to test how multiply requests are perfectly handled even by 1st case, just open separate tabs in browser and start requests almost at the same time.
Upvotes: 3
Reputation: 1
Actually, The problem is not from your controller, the tomcat server create a thread for each request you send, the problem is from the browser itself if you send 2 requests to the same endpoint the browser stalls the second request until the first one get the response "I don't know why or how to fix it", and you will find that the actual time server take is the time form sending the request to getting the first byte of the response TTFB time check this screenshot from browser Networking of the second request, you can use other browser or another device connected to your network to test sending 2 requests at the same time
Upvotes: 0
Reputation: 753
I am using Spring since 2009, I know that their Controller is Singleton. But it doesn't mean they process your request sequentially(wait for one to finish, then execute the next one).
The example codes from Spring Boot website are able to handle parallel request. It will create singleton instance of HelloController
but Spring is able to call index()
multiple times at the same time(parallel).
@RestController
public class HelloController {
@RequestMapping("/")
public String index() {
return "Greetings from Spring Boot!";
}
}
Upvotes: 1
Reputation: 8308
The controller being a singleton has nothing to do with whether it can be accessed concurrently.
You really shouldn't need to use request based scoping unless you have some mutable field that cant be shared across threads, but implementing something like that is probably just bad design.
I imagine the reason you are seeing the two requests take 30 seconds is because you arent actually making concurrent requests, rather you are waiting for the first request to complete before starting the second.
Upvotes: 2