Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring retry not working in RestController

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?

like image 280
falcon Avatar asked Apr 05 '16 05:04

falcon


People also ask

How do I enable retry in spring boot?

First, you need to enable Spring Retry. You can achieve this by adding the @EnableRetry annotation to your @SpringBootApplication or @Configuration class. You can now use @Retryable to annotate any method to be a candidate or retry and @Recover to specify fallback methods.

Does spring retry block thread?

Does the default spring-retry implementation block threads while retrying? The implementation in github indicates that it does.

Which tool will provide declarative retry support via spring Retry?

Spring Retry library (https://github.com/spring-projects/spring-retry) provides a declarative support to retry failed operations as well as fallback mechanism in case all the attempts fail.

What is @retryable in spring boot?

Spring Retry provides the ability to automatically re-invoke a failed operation. This is helpful when errors may be transient in nature. For example, a momentary network glitch, network outage, server down, or deadlock. You can configure the. spring-retry.


1 Answers

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.

like image 191
nicholas.hauschild Avatar answered Sep 29 '22 21:09

nicholas.hauschild