Search code examples
javahttpresponseretrypolicyresilience4j

Java resilience4j Retry policy goes infinite after 2 retries


I am using the resilience4j Retry policy to call the HttpGet request and for testing purposes,
I have set retryOnResult to retry when HttpGet request returns 200 status code.
It successfully retries when maxAttempts is set to 2.

For maxAttempts > 2 application goes in infinite state.

public class App {
    public static void main(String[] args) {
        HttpClient client = HttpClients.createDefault();
        HttpRequest request = new HttpGet("https://jsonplaceholder.typicode.com/todos/1");
        HttpResponse response;
        try {
            RetryConfig retryConfig = RetryConfig.<HttpResponse>custom().waitDuration(Duration.ofSeconds(2))
                    .maxAttempts(3).retryOnResult(s -> {
                        return s.getStatusLine().getStatusCode() == 200;
                    }).build();
            RetryRegistry registry = RetryRegistry.of(retryConfig);
            Retry retry = registry.retry("Http client");
            retry.getEventPublisher().onRetry(e -> {
                System.out.println("Retrying");
            });

            CheckedFunction0<HttpResponse> retryableSupplier = Retry.decorateCheckedSupplier(retry,
                    () -> client.execute((HttpUriRequest) request));
            response = Try.of(retryableSupplier).get();
            HttpEntity entity = response.getEntity();
            System.out.println(EntityUtils.toString(entity));
        } catch (ClientProtocolException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}

pom.xml:

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>3.8.1</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.3</version>
    </dependency>
    <dependency>
        <groupId>io.github.resilience4j</groupId>
        <artifactId>resilience4j-circuitbreaker</artifactId>
        <version>1.1.0</version>
    </dependency>

    <dependency>
        <groupId>io.github.resilience4j</groupId>
        <artifactId>resilience4j-retry</artifactId>
        <version>1.1.0</version>
    </dependency>
</dependencies>

Solution

  • Finally found the root cause. Issue is not with the resiliency4j. But in above scenario same HttpGet request is called multiple times in retry scenario. And by default httpclient creates a pool with size of 2. So after 2 is used, it waits indefinitely trying to get the third connection from the pool.

    Final Working Code :

    public class App {
        public static int retryCounter = 0; 
        public static void main(String[] args) {
    
            int maxAttempts = 4;
            HttpClient client = HttpClients.createDefault();
            HttpRequest request = new HttpGet("https://jsonplaceholder.typicode.com/todos/1");
            HttpResponse response;
            try {
    
                RetryConfig retryConfig = RetryConfig.<HttpResponse>custom().waitDuration(Duration.ofSeconds(1))
                        .maxAttempts(maxAttempts).retryOnResult(s -> {
                            try {
                                if (s.getStatusLine().getStatusCode() == 200) {
    
                                    if (retryCounter < maxAttempts -1) {
                                        s.getEntity().getContent().close();
                                    }
                                    return true;
                                } else {
                                    return false;
                                }
                            } catch (UnsupportedOperationException e1) {
                                return true;
                            } catch (IOException e1) {
                                // TODO Auto-generated catch block
                                return true;
                            }
    
                        }).build();
                RetryRegistry registry = RetryRegistry.of(retryConfig);
                Retry retry = registry.retry("Http client");
                retry.getEventPublisher().onRetry(e -> {
                    retryCounter ++;
                    System.out.println("Retrying" + e.getNumberOfRetryAttempts());
    
                });
    
                CheckedFunction0<HttpResponse> retryableSupplier = Retry.decorateCheckedSupplier(retry, () -> {
    
                    HttpResponse res = client.execute((HttpUriRequest) request);
                    return res;
                });
                response = (CloseableHttpResponse) Try.of(retryableSupplier).get();
                HttpEntity entity = response.getEntity();
                System.out.println(EntityUtils.toString(entity));
            } catch (ClientProtocolException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block`enter code here`
                e.printStackTrace();
            }
        }