Java resilience4j 重试策略在 2 次重试后变为无限
Java resilience4j Retry policy goes infinite after 2 retries
我正在使用 resilience4j
重试策略来调用 HttpGet
请求并出于测试目的,
我已将 retryOnResult
设置为在 HttpGet
请求 returns 200
状态码时重试。
当 maxAttempts
设置为 2
时,它会成功重试。
对于 maxAttempts > 2
应用程序进入无限状态。
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>
那不是真的。如果尝试次数大于maxAttempts,则返回最后的结果给客户端。这不是无限循环。
public static void main(String[] args) {
String response;
RetryConfig retryConfig = RetryConfig.<String>custom().waitDuration(Duration.ofMillis(100))
.maxAttempts(3).retryOnResult(s -> {
return s.contains("Hello");
}).build();
RetryRegistry registry = RetryRegistry.of(retryConfig);
Retry retry = registry.retry("Http client");
retry.getEventPublisher().onRetry(e -> {
System.out.println("Retrying");
});
CheckedFunction0<String> retryableSupplier = Retry.decorateCheckedSupplier(retry,
() -> "Hello World");
response = Try.of(retryableSupplier).get();
System.out.println(response);
}
结果
Retrying
Retrying
Hello World
第三次尝试也是"failed",但是结果返回给客户端
终于找到根本原因了。问题不在于 resiliency4j。但在上述场景中,相同的 HttpGet 请求在重试场景中被多次调用。默认情况下 。所以在使用 2 之后,它会无限期地等待,试图从池中获取第三个连接。
最终工作代码:
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();
}
}
我正在使用 resilience4j
重试策略来调用 HttpGet
请求并出于测试目的,
我已将 retryOnResult
设置为在 HttpGet
请求 returns 200
状态码时重试。
当 maxAttempts
设置为 2
时,它会成功重试。
对于 maxAttempts > 2
应用程序进入无限状态。
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>
那不是真的。如果尝试次数大于maxAttempts,则返回最后的结果给客户端。这不是无限循环。
public static void main(String[] args) {
String response;
RetryConfig retryConfig = RetryConfig.<String>custom().waitDuration(Duration.ofMillis(100))
.maxAttempts(3).retryOnResult(s -> {
return s.contains("Hello");
}).build();
RetryRegistry registry = RetryRegistry.of(retryConfig);
Retry retry = registry.retry("Http client");
retry.getEventPublisher().onRetry(e -> {
System.out.println("Retrying");
});
CheckedFunction0<String> retryableSupplier = Retry.decorateCheckedSupplier(retry,
() -> "Hello World");
response = Try.of(retryableSupplier).get();
System.out.println(response);
}
结果
Retrying
Retrying
Hello World
第三次尝试也是"failed",但是结果返回给客户端
终于找到根本原因了。问题不在于 resiliency4j。但在上述场景中,相同的 HttpGet 请求在重试场景中被多次调用。默认情况下
最终工作代码:
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();
}
}