Reputation: 1434
I am trying spring retry and I am facing a strange issue. When I use the retry annotation on a method within a Rest Controller, the retry does not work. But if I move that method to a separate service class, it works. The following code does not work:
@RestController
public class HelloController {
@RequestMapping(value = "/hello")
public String hello() {
return getInfo();
}
@Retryable(RuntimeException.class)
public String getInfo() {
Random random = new Random();
int r = random.nextInt(2);
if (r == 1) {
throw new RuntimeException();
} else {
return "Success";
}
}
}
But the following does:
@RestController
public class HelloController {
@Autowired
private SomeService service;
@RequestMapping(value = "/hello")
public String hello() {
String result = service.getInfo();
return result;
}
}
@Service
public class SomeService {
@Retryable(RuntimeException.class)
public String getInfo() {
Random random = new Random();
int r = random.nextInt(2);
if (r == 1) {
throw new RuntimeException();
} else {
return "Success";
}
}
}
My question is why the @Retryable
is not working when used in the controller?
Upvotes: 9
Views: 6304
Reputation: 42849
The issue you are seeing is due to how you are calling your getInfo()
method.
In the first example, you are calling getInfo()
from within the same spring managed bean. In the second example you are calling getInfo()
from a different spring managed bean. This distinction is subtle, but very important, and it is very likely what is causing your issues.
When you use the @Retryable
annotation, Spring is creating a proxy around your original bean so that they can do special handling in special circumstances. In this specific case, Spring applies an Advice that will delegate a call to your actual method, catching RuntimeException
's that it may throw, and retrying the invocation of your method according to the configuration of your @Retryable
annotation.
The reason this proxy matters in your case is that only external callers see the proxy advice. Your bean has no knowledge that it is proxied, and only knows that its methods are being called (by the proxy advice). When your bean calls a method on itself, no further proxying is involved, which is why the retrying does not actually occur.
Upvotes: 22