feign-reactor-core ReactiveRetryPolicy causing a huge delay in the api response from webTestClient

404 Views Asked by At

I have an existing application on spring boot 2.4.4 running on Java 11. I am migrating to Java 17 and Spring boot 2.7.10. I am using feign-reactor-core to enable feign and have configured a retry policy

pom.xml

       <dependency>
            <groupId>com.playtika.reactivefeign</groupId>
            <artifactId>feign-reactor-cloud</artifactId>
            <version>3.3.0</version>
        </dependency>

        <dependency>
            <groupId>com.playtika.reactivefeign</groupId>
            <artifactId>feign-reactor-spring-configuration</artifactId>
            <version>3.3.0</version>
        </dependency>

        <dependency>
            <groupId>com.playtika.reactivefeign</groupId>
            <artifactId>feign-reactor-webclient</artifactId>
            <version>3.3.0</version>
        </dependency>

        <dependency>
            <groupId>org.projectreactor.spring</groupId>
            <artifactId>reactor-spring-context</artifactId>
            <version>1.1.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-core</artifactId>
            <version>3.4.28</version>
        </dependency>

Configuration

@Configuration
public class ReactiveFeignClientConfiguration {

    @Bean
    public ReactiveRetryPolicy reactiveRetryPolicy(final ReactiveFeignRetryConfiguration reactiveFeignRetryConfiguration) {
        return new FilteredReactiveRetryPolicy(new MyFeignReactiveRetryPolicy(Schedulers.parallel(), reactiveFeignRetryConfiguration),
                throwable -> throwable instanceof RetryableException || throwable instanceof ReadTimeoutException);
    }
}

MyFeignReactiveRetryPolicy.java

package com.my.client.reactive.rest.client.retry;

import feign.ExceptionPropagationPolicy;
import lombok.extern.slf4j.Slf4j;
import com.my.client.reactive.rest.client.config.ReactiveFeignRetryConfiguration;
import reactivefeign.retry.SimpleReactiveRetryPolicy;
import reactor.core.scheduler.Scheduler;

@Slf4j
public class MyFeignReactiveRetryPolicy extends SimpleReactiveRetryPolicy {

    private final int maxAttempts;
    private final long interval;
    private final long maxInterval;

    public MyFeignReactiveRetryPolicy(Scheduler scheduler, ReactiveFeignRetryConfiguration reactiveFeignRetryConfiguration) {
        super(scheduler, ExceptionPropagationPolicy.UNWRAP);
        this.maxAttempts = reactiveFeignRetryConfiguration.getMaxAttempts();
        this.interval = reactiveFeignRetryConfiguration.getInterval();
        this.maxInterval = reactiveFeignRetryConfiguration.getMaxInterval();
    }

    @Override
    public long retryDelay(Throwable error, int attemptNo) {
        log.info("Feign attempt {} due to {}", attemptNo, error.getMessage());
        if (attemptNo == maxAttempts) {
            log.error("Max Attempts reached - {}", attemptNo);
            log.error("Error after max attempts - ", error);
            return -1;
        }
        return this.interval;
    }

}

Test Controller

@Slf4j
@RestController
public class ReactiveTestController {

    @Autowired
    private IIntegrationTestController controller;

    @PostMapping("/submitRequest")
    public Mono<String> submitTestRequest(@RequestBody final Object obj) {
        log.info("Inside controller with content :{}", obj);
        return controller.checkHealth();
    }
}
@ReactiveFeignClient(name = "test-client")
public interface IIntegrationTestController {

    @GetMapping("/feigntest/health")
    Mono<String> checkHealth();

}

Test class

@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
        classes = {MyApplication.class}) // spring runner application, no additional code
@AutoConfigureWebTestClient(timeout = "600000")
@DirtiesContext
public class Test {
    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private WebTestClient webTestClient;

    @Autowired
    private WireMockServer mockHttpServer;

    @Test
    void testFeign() throws Exception {
        mockHttpServer.start();
        final StubMapping stubMapping = stubFor(get(urlEqualTo("/feigntest/health"))
                .willReturn(aResponse().withHeader("Content-Type", "application/json")
                        .withBody(objectMapper.writeValueAsString(new APIError(new FeignClientException(500, "error-error"), 500, "error")))
                        .withStatus(500)));

        Object obj = new Object();
        WebTestClient.ResponseSpec exchange = webTestClient.post().uri("/submitRequest")
                .contentType(MediaType.APPLICATION_JSON)
                .bodyValue(obj)
                .exchange();

        exchange.expectStatus().is5xxServerError();
        exchange.expectBody().consumeWith(body -> {
            Assertions.assertNotNull(body.getResponseBody());
        });
       mockHttpServer.stop();
    }
}

I am getting success from this test case in Java 17 with Spring 2.7.10, but its taking a lot of time in my system (MacOS) ~26 seconds

In Java 11 with Spring boot 2.4.4, this didn't take this long (gets success in under a second).

Also If I remove the ReactiveRetryPolicy bean, then its working fine and getting successful in less than a second in the upgraded versions.

What is going wrong here?

0

There are 0 best solutions below