Java “实施的最佳方式”;“重试”;当到达api端点时?
我正在使用ApacheHttpClient 我有一个Java方法(在Java微服务中),它向外部端点(我不拥有的端点)发出HttpPOST请求。通常情况下,一切正常,但有时端点出现故障并失败。代码如下所示(简化): 我没有编写原始代码,但正如您所看到的,它似乎发出了一个请求,虽然请求重试计数大于0(看起来总是这样),但它将尝试向url发出帖子。由于某种原因,它看起来有一个断点,因此在它跳入Java “实施的最佳方式”;“重试”;当到达api端点时?,java,api,http,endpoint,Java,Api,Http,Endpoint,我正在使用ApacheHttpClient 我有一个Java方法(在Java微服务中),它向外部端点(我不拥有的端点)发出HttpPOST请求。通常情况下,一切正常,但有时端点出现故障并失败。代码如下所示(简化): 我没有编写原始代码,但正如您所看到的,它似乎发出了一个请求,虽然请求重试计数大于0(看起来总是这样),但它将尝试向url发出帖子。由于某种原因,它看起来有一个断点,因此在它跳入try块之后,它总是会中断,并且没有重试机制 Java中是否有一种通用的设计模式来实现命中外部端点的重试模式
try
块之后,它总是会中断,并且没有重试机制
Java中是否有一种通用的设计模式来实现命中外部端点的重试模式?我知道在Javascript中,您可以使用Fetch API并返回一个承诺,Java有类似的功能吗?像GCP和AWS这样的云平台通常都有自己的重试策略,这应该是首选方法 如果您想扮演自己的重试策略角色,指数退避可以是一个很好的起点 它可以是基于注释的,您可以在其中注释客户机方法。例如, 您可以按如下方式注释API方法:
public class RetryMethodInterceptor implements MethodInterceptor {
private static final Logger logger = Logger.getLogger(RetryMethodInterceptor.class.getName());
@Override
public Object invoke(MethodInvocation methodInvocator) throws Throwable {
Retry retryAnnotation = methodInvocator.getMethod().getAnnotation(Retry.class);
Set<Class<? extends Throwable>> retriableExceptions =
Sets.newHashSet(retryAnnotation.retryOnExceptions());
String className = methodInvocator.getThis().getClass().getCanonicalName();
String methodName = methodInvocator.getMethod().getName();
int tryCount = 0;
while (true) {
try {
return methodInvocator.proceed();
} catch (Throwable ex) {
tryCount++;
boolean isExceptionInAllowedList = isRetriableException(retriableExceptions, ex.getClass());
if (!isExceptionInAllowedList) {
System.out.println(String.format(
"Exception not in retry list for class: %s - method: %s - retry count: %s",
className, methodName, tryCount));
throw ex;
} else if (isExceptionInAllowedList && tryCount > retryAnnotation.maxTries()) {
System.out.println(String
.format(
"Exhausted retries, rethrowing exception for class: %s - method: %s - retry count: %s",
className, methodName, tryCount));
throw ex;
}
System.out.println(String.format("Retrying for class: %s - method: %s - retry count: %s",
className, methodName, tryCount));
}
}
}
private boolean isRetriableException(Set<Class<? extends Throwable>> allowedExceptions,
Class<? extends Throwable> caughtException) {
for (Class<? extends Throwable> look : allowedExceptions) {
// Only compare the class names we do not want to compare superclass so Class#isAssignableFrom
// can't be used.
if (caughtException.getCanonicalName().equalsIgnoreCase(look.getCanonicalName())) {
return true;
}
}
return false;
}
}
@重试(maxTries=3,retryOnExceptions={RpcException.class})
public UserInfo getUserInfo(字符串userId)
@已记录
@保留(RetentionPolicy.RUNTIME)
@目标(ElementType.METHOD)
公共@接口重试{
int maxTries()默认值为0;
/**
*如果引发以下异常之一,请尝试重试。
*@返回适用异常的数组
*/
ClassAPI的终结点是什么,是AWS、GCP等吗?重试已经是ApacheHttpClient
的一部分。promise是JS代表asyn操作,promise本身不会在失败时重试。如果你想看的话,我用我已有的代码更新了我的问题。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Retry {
int maxTries() default 0;
/**
* Attempt retry if one of the following exceptions is thrown.
* @return array of applicable exceptions
*/
Class<? extends Throwable> [] retryOnExceptions() default {Throwable.class};
}
public class RetryMethodInterceptor implements MethodInterceptor {
private static final Logger logger = Logger.getLogger(RetryMethodInterceptor.class.getName());
@Override
public Object invoke(MethodInvocation methodInvocator) throws Throwable {
Retry retryAnnotation = methodInvocator.getMethod().getAnnotation(Retry.class);
Set<Class<? extends Throwable>> retriableExceptions =
Sets.newHashSet(retryAnnotation.retryOnExceptions());
String className = methodInvocator.getThis().getClass().getCanonicalName();
String methodName = methodInvocator.getMethod().getName();
int tryCount = 0;
while (true) {
try {
return methodInvocator.proceed();
} catch (Throwable ex) {
tryCount++;
boolean isExceptionInAllowedList = isRetriableException(retriableExceptions, ex.getClass());
if (!isExceptionInAllowedList) {
System.out.println(String.format(
"Exception not in retry list for class: %s - method: %s - retry count: %s",
className, methodName, tryCount));
throw ex;
} else if (isExceptionInAllowedList && tryCount > retryAnnotation.maxTries()) {
System.out.println(String
.format(
"Exhausted retries, rethrowing exception for class: %s - method: %s - retry count: %s",
className, methodName, tryCount));
throw ex;
}
System.out.println(String.format("Retrying for class: %s - method: %s - retry count: %s",
className, methodName, tryCount));
}
}
}
private boolean isRetriableException(Set<Class<? extends Throwable>> allowedExceptions,
Class<? extends Throwable> caughtException) {
for (Class<? extends Throwable> look : allowedExceptions) {
// Only compare the class names we do not want to compare superclass so Class#isAssignableFrom
// can't be used.
if (caughtException.getCanonicalName().equalsIgnoreCase(look.getCanonicalName())) {
return true;
}
}
return false;
}
}