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

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.

Related

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.

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

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.

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 rest api versioning

In my spring controller, I have 2 rest api methods. example: getUser, getRole
One client is accessing it by like "/api/v1".
Now I want to update one of the methods. i.e., getRole. So the new method/version will be "/api/v2".
But no change in methods of v1. i.e., "/api/v1".
How to handle the rest methods with both versions in the same project ?
I mean, getUser rest API should support both "/api/v1" and "/api/v2".
And getRole rest API should support both versions but different functionality (example: database changed, logic changed).
In simple words,
1. getUser will have 1 method which supports both versions.
2. getRole will have 2 methods for each versions.
Please help me here.
If you want to do use separate method for both version you can by defining different value in #RequestMapping
method 1
#RequestMapping(
value = "baseurl/v1/role",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
and
#RequestMapping(
value = "baseurl/v2/role",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
but if you want to handle it in same method you can using
method 2: use #PathVariable
#RequestMapping(
value = "baseurl/{version}/role",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public returnType methodName(#PathVariable("version") String version){
// code to check version
}
method 3: use #RequestHeader
#RequestMapping(
value = "baseurl/role",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public returnType methodName(#RequestHeader("version") String version){
// code to check version
}
But as you said you have different version of api's prefer to manage them in separate controller using #RequestMapping at class level
method 4:
#RestController
#RequestMapping("/v1")
public class anyController {
}
and
#RestController
#RequestMapping("/v2")
public class anyController {
}
It really depends on your use case and what all is changing. There are technically many different paths you can take, but I will describe two that sound like they would work for you.
Create path param for v1 and add conditional that checks to see if the path param is v2 and call different method.
Create new path for api/v2, add changes functionality and call v1 endpoint method.
This really gets into specifics and should probably be evaluated on which way you should take it, depending on how the existing code is implemented.
I would do the following approach
Define a version at the application level (Start with /v1) -- this version is changed only when you want to make bigger changes to your whole API and is usually stable.
Resources (roles, users) etc. should be versioned additionally using content negotiation via the headers
e.g.
GET /v1/users/503deb67-ff6e-4d1c-a225-408b910b7252/ HTTP/1.1
Accept: application/vnd.yourorg.users-v1+json
Here the client uses content negotiation for the specific resource she is interested in via the HTTP header
See https://www.mashery.com/blog/ultimate-solution-versioning-rest-apis-content-negotiation and http://blog.ploeh.dk/2015/06/22/rest-implies-content-negotiation/ for more details
There are many ways, but most likely you want to keep the code as decoupled as possible. This makes keeping the versions in separate classes a good option:
V1Controller.java:
#RestController
#RequestMapping("/api/v1")
public class V1Controller{
// version 1 api
}
V2Controller.java :
#RestController
#RequestMapping("/api/v2")
public class V2Controller{
// version 2 api
}
But for a even higher degree of decoupling you could have two different webapps deployed on the same Tomcat or Jetty server - version 1 under the context path "/api/v1" and version 2 on the context path "/api/v2". The webapps would simply be builds of different versions of the same code (or builds of different branches - if you're using git).

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