How to implement request timeout management in an AOP way in Spring Boot - spring

currently I'm exploring approaches to implement 'request timeout management in an AOP way in Spring Boot' with several restrictions. The requirements/restrictions are stated as below:
The original purpose is that if the processing time of an api request exceeds 5 seconds, then directly return timeout result instead of continue processing
The rest api to be monitored is implemented by standard spring mvc rest controller. All apis inside are returning json strings like this:
#RestController
public class xxxxxx {
#RequestMapping(value = "xxxxxxx")
public String xxxxxx(#RequestParam(value = "xxxx", required = true) String xxxx) {
....
return json.toString();
}
}
The timeout logic is required to be implemented by AOP
(The real mean part)
No changes should be made to the controllers, which means: Request generation approach should not be changed; Return type should not be changed(No 'Callable<...>' allowed)
I have already found 1 answer(Async approach) which can perfectly resolve the problem itself with spring async, and the timeout return result is very pretty, but it's changing the return type, and also touching the code in controller. I also found one solution(AOP approach) which is using AOP, but the scenario is quite different from mine. It's already moving some business logic into AOP class, but I'm not allowed to touch the controller code. I would be grateful if anyone can provide a solution. Solutions that can't meet all the restrictions but are minimizing the differences are also admitted.

Since there is still no response to this question, I will put my own temporary solution here.
I'm using Hystrix dependency.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.0.RELEASE</version>
</dependency>
It's well integrated with springboot, so the configuration is easy. Once properly configured, need to append an annotation on the request method that requires timeout handling. e.g.
#HystrixCommand(fallbackMethod="fallback")
#RequestMapping(value = "xxxxxxx")
public String xxxxxx(#RequestParam(value = "xxxx", required = true) String xxxx) {
....
return json.toString();
}
And need to add a fallback method with the name mapped to the value of 'fallbackMethod' inside annotation:
public String fallback() {
...
}
The timeout time value can be globally configured inside application.properties
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=3000
hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds=3000
This is still not concise in these points:
Need to copy/paste this annotation for every method
Need to copy/paste the fallback method in every place hystrix is used
For hystrix fallback method itself, the parameter type and number need to be exactly same with the hystrix marked method. Currently I'm using several overloading method called 'fallback' for this, in each controller
But at least it's not changing method return types and code inside methods anymore and is the best solution I can think of currently. Will perform update once I find better solutions.

Related

Putting Spring WebFlux Publisher inside Model, good or bad practice?

I'm working on a code audit on a SpringBoot Application with Spring WebFlux and the team is putting Publisher directly inside the Model and then resolve the view.
I'm wondering if it is a good or bad practice because it seems to be working but in that case, which component is in charge of executing the Publisher ?
I think that it's the ViewResolver and it should not be its job. What do you think ?
Moreover, if the Publisher is not executed by the Controller, the classes annotated by #ControllerAdvice such like ExceptionHandler won't work if these Publisher return an error, right ?
Extract of the Spring WebFlux documentation :
Spring WebFlux, unlike Spring MVC, explicitly supports reactive types in the model (for example, Mono or io.reactivex.Single). Such asynchronous model attributes can be transparently resolved (and the model updated) to their actual values at the time of #RequestMapping invocation, provided a #ModelAttribute argument is declared without a wrapper, as the following example shows:
#ModelAttribute
public void addAccount(#RequestParam String number) {
Mono<Account> accountMono = accountRepository.findAccount(number);
model.addAttribute("account", accountMono);
}
#PostMapping("/accounts")
public String handle(#ModelAttribute Account account, BindingResult errors) {
// ...
}
In addition, any model attributes that have a reactive type wrapper are resolved to their actual values (and the model updated) just prior to view rendering.
https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#webflux-ann-modelattrib-methods
Doesn't come as a shock to me.
Actually seems to be a good trade off between complexity and efficiency when the Publisher is handling complex stuff.
It has the advantage of executing the Publisher only if and when needed.
Although it might be a problem if the ModelMap handler does not have the capacity to use it properly.
As for the exceptional cases, maybe you do not want it to be executed and just printed, thus failing faster.
As for the question about what is executing the Publisher, a specific ViewResolver can be used as it is the component responsible for the "rendering". IMHO that's it's job. I do not know if a standard ViewResolver can be used for detecting values vs publishers and handle those automagically, yet this seems completely doable and efficient.

How to handle optional service dependency of service in Spring Boot?

I've a service called InformationService. It optionally depends on ReleaseService. If the property external.releaseservice.url is set, the InformationService shall make a request to it and enrich it's own response with aggregate data.
If however the url is not defined, the response shall simply return a string like not available for the fields in question.
What's the spring boot way to achieve this? Inject an Optional<ReleaseService> into the InformationService? Is there another pattern for this?
You have three ways to achieve this.
#Autowired(required = false)
This works, but it requires field injection, which is not great for unit tests as is well known.
#Autowired(required = false)
private ReleaseService releaseService;
Java Optional type
As you said, Optional will also do the job and it allows you to stick to constructor injection. This is my suggested approach.
Spring's ObjectProvider
There is also an ObjectProvider designed specifically for injection points which you can use to achieve this as follows.
public InformationService(ObjectProvider<ReleaseService> releaseServiceProvider) {
this.releaseService = releaseServiceProvider.getIfAvailable();
}
It is more cumbersome and therefore I would avoid it. There is an advantage that allows you to specify a default instance if none is available but I guess that is not what you need.

Is it possible to use another circuit breaker over fallback method?

I have a requirement to implement circuit breaker in a java based microservice such that if there are defined number of failures from backendA then fallback method should call to another backendB, and if backendB also fails then there should be another fallback method to return error from Java API itself.Is it possible, more importantly is it advisable to implement such design.If someone can give any reference or examples where such patterns is used. I will be using resilience4j library to do so. The code structure will look something like this:
#CircuitBreaker(name = "backendA", fallbackMethod = "fallback1")
{Method to call backendA}//Threshold value : 10 requests
#CircuitBreaker(name = "backendB", fallbackMethod = "fallback2")
private String fallback1() { Method to call backendB} // Threshold value : 2 requests
private String fallback2() { Method to return error}
This won't work due to the way Spring AOP (proxies) work.
A fallback method cannot have Annotations.
Creating another class and a new method to call the alternate system worked for me. Basically a circuit breaker cannot be applied on the fallback method in the same class, so calling another method in a new class and adding a Circuit breaker there, resolved the issue.

Spring controller method invocation advice

I have a controller that exposes the following endpoint:
#RequestMapping("/all-users")
List<User> getAllUsers() {
...
}
I have also an annotation that helps me out with versioning of those endpoints, which ends up on something like this:
#RequestMapping("/all-users")
#Version(version=1, latests=LATEST_ALL_USERS)
List<User> getAllUsers() {
...
}
Now I want to introduce an additional standard behavior to all handlers mapped wish method contains #Version annotation which will simply wrap the response object into another object which contains the current version and latest version of the invoked method. Some information to build this object are provided by #PathVariable parameters. I'm trying to find a hook that allows me that but no luck so far.
I tried first to have a custom RequestResponseBodyMethodProcessor but if I add it will not take any effect because the original RequestResponseBodyMethodProcessor comes before and I don't want to remove the ResponseBody from my endpoints.
Afterward I tried to go for the mapping instead, once I cannot handle it on the processor, maybe I could handle that on mapping time introducing my code pre and post method invocation, but got stuck on the point where mapping is registered where a method object is needed, not allowing me to introduce my advice code.
Is there any way to get this done?
Edit:
Some of the information needed to build the new returned object are provided as #PathVariables, and are available on end-point method call.

Spring boot actuator - Implement custom metrics

I would like to implement custom metric or statistics to my spring boot rest web service using actuator but i am not able to find simple tutorials.
For example:
how to show how many times a certain controller was called and what exact parameter field was filled?
how can i create a metric that when its URL is called, it runs certain query and shows back a json with some result
This seems like a good scenario for AOP (Aspect Oriented Programing) as this will allow you to separate this statistic logic from the business logic.
Have a look at Spring doc for more info about AOP and how to achieve that with Spring.
You can then define a pointcut on your controller and have a service for counting (and probably then storing) the data.
Refer below link
AOP Example
For point two the solution is to create an endpoint class (it can be or not a rest controller class). For example:
#Component
#RestControllerEndpoint(id = "pfm-statistics")
public class StatisticsEndpoint {
#GetMapping(value = "/", produces = "application/vnd.openxmlformats-
officedocument.spreadsheetml.sheet")
#ResponseBody
public byte[] generateStatisticsAsExcel() {
...
Note that the ID is the path to be called from URL. We can create a simple endpoint too and just return a string if we want. In this case instead of #RestControllerEndpoint annotation we can use #Endpoint, as a side note, the id should always contain dash

Resources