Reputation: 21
I have a Rest Controller method (It could be a GET or a POST or anything) and the processing takes minimum 20 minutes or more to execute. The consumer will wait for maximum 10 seconds only. How should we handle this situation properly ? Is there a design pattern or anything ? I am requesting for suggestions. This was asked in an interview.
@Controller
public class TestController {
@RequestMapping("/")
public @ResponseBody String someMethod() {
// Logic containing big calculation taking 20 minutes
return "Some response";
}
}
Upvotes: 0
Views: 81
Reputation: 10717
If the client is calling a process that will take too long for answering in real time, make that process asynchronous.
In the controller, write a command with the information about what to do to a message queue or a kafka topic. Then put a listener to listen to that topic and do the task.
Also from the controller, return a response to the client telling that he can consult about the result of his action later. Give him a link or id to do that.
Upvotes: 1
Reputation: 589
For the short answer, you have to use a technique called Long Polling.
Long answer please read on.
The answer to your question can be more subjective, as we have to understand the scenario. what client is doing? Does he want to get the result in the same HTTP request? or he is not interested in the result or he can check the result through mail or some other channel?
Let say your client is interested in the result once 20 min has elapsed. In this scenario, you have to implement Long polling in your system. In spring we have a class called DeferredResult which can help you to achieve the result.
@RestController
@RequestMapping("/api")
public class BakeryController {
@GetMapping("/bake/{bakedGood}")
public DeferredResult<String> publisher(@PathVariable String bakedGood, @RequestParam Integer bakeTime) {
DeferredResult<String> output = new DeferredResult<>();
try {
Thread.sleep(bakeTime);
output.setResult(format("Bake for %s complete and order dispatched. Enjoy!", bakedGood));
} catch (Exception e) {
// ...
}
return output;
}
}
Ref:- https://www.baeldung.com/spring-mvc-long-polling
Now let say your client is not interested in the result. He just wants to execute some API, and this service will do the work that it has been intended for and it will publish the result somewhere. In this scenario, you can use async processing through the Active MQ or Kafka where your consumer will process the result, and it will store the result to the desired channel. By implementing this way you can immediately return the request releasing the thread.
A example using this approach with the help of Active MQ, and JMS template is below :-
@RestController
public class TestController {
@RequestMapping("/")
public ResponseEntity String someMethod(String requestPayload) {
// This will be async. It will put the message in the queue and
// will return the response.
jmsTemplate.send("your_queue_name", requestPayload);
ResponseEntity.status(HttpStatus.OK).build();
}
}
Upvotes: 1
Reputation: 57259
The representation sent with this response ought to describe the request's current status and point to (or embed) a status monitor that can provide the user with an estimate of when the request will be fulfilled.
In other words, after you have established that the request is correct and authorized, and that you have the capability to address the request, send back to the client a document with an estimate (if you have one) for when the work will be ready, and a link to a page that can be used to check on the status of the pending result.
That will probably mean something like obtaining/generating a unique identifier for this request, which can later be used to look up how things are going.
Upvotes: 1