0

We are in the need of adding retries when making calls to an API that has Oauth2 from Spring.

We haven't figured out how to do it in an easy way. We even tried with an interceptor but we have no luck.

Here's our code:

Application.java

@EnableRetry
@SpringBootApplication
public class Application {

    public static void main(String args[]) {
        SpringApplication.run(Application.class);
    }

    @Bean
    public OAuth2RestTemplate oAuth2RestTemplate(ClientHttpRequestInterceptor interceptor) {
        List<String> scopes = new ArrayList<>();
        scopes.add("some-scope");

        ClientCredentialsResourceDetails resourceDetails = new ClientCredentialsResourceDetails();
        resourceDetails.setAccessTokenUri("tokenUrl");
        resourceDetails.setClientId("client-id");
        resourceDetails.setClientSecret("client-secret");
        resourceDetails.setScope(scopes);

        OAuth2RestTemplate oAuth2RestTemplate = new OAuth2RestTemplate(resourceDetails);

        List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
        interceptors.add(interceptor);
        oAuth2RestTemplate.setInterceptors(interceptors);
        return oAuth2RestTemplate;
    }

    @Bean
    public CommandLineRunner run(OAuth2RestTemplate oAuth2RestTemplate) throws Exception {
        return args -> {
            oAuth2RestTemplate.getForObject(
                    "some-url-that-returns-error.com", Quote.class);
        };
    }
}

MyInterceptor.java

@Component
public class MyInterceptor implements ClientHttpRequestInterceptor {

    @Override
    public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution execution) throws IOException {
        return interceptWithRetry(httpRequest, bytes, execution);
    }

    @Retryable
    private ClientHttpResponse interceptWithRetry(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution execution) throws IOException {
        System.out.println("====================================");
        return execution.execute(httpRequest, bytes);
    }
}

And the dependencies in our pom.xml

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security.oauth</groupId>
            <artifactId>spring-security-oauth2</artifactId>
            <version>2.3.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.retry</groupId>
            <artifactId>spring-retry</artifactId>
            <version>1.2.4.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

When we run this and there is an error we can not see the call beign retried, no matter what parameters we pass down to @Retryable, the interceptor is called only once.

Could somebody provide some guidelines on this?

Thanks

Cris Pinto
  • 293
  • 3
  • 18

1 Answers1

0

We still don't know the reason why Retryable didn't work in the interceptor. We ended up moving the annotation to a method in a Service and got rid completely of the interceptor.

SomeService.java

@Service
public class SomeService {

    private OAuth2RestTemplate restTemplate;

    public SomeService(OAuth2RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    @Retryable
    public Quote getSomething() {
        System.out.println("============= THIS WILL THROW AN EXCEPTION =================");
        return restTemplate.getForObject(
                "some-url-that-returns-error.com", Quote.class);
    }

}

This works. However, it would be nice to have something to avoid repeating @Retryable(params) on every method of every service.

For now, I will mark the question as answered.

Cris Pinto
  • 293
  • 3
  • 18