|
|
@@ -42,18 +42,6 @@ public class FeatureV2Client {
|
|
|
@GrpcClient("recommend-feature")
|
|
|
private FeatureV2ServiceGrpc.FeatureV2ServiceBlockingStub client;
|
|
|
|
|
|
- /**
|
|
|
- * 最大重试次数
|
|
|
- * 说明:对于网络连接问题,重试可以触发连接重建
|
|
|
- */
|
|
|
- private static final int MAX_RETRY_ATTEMPTS = 2;
|
|
|
-
|
|
|
- /**
|
|
|
- * 重试延迟(毫秒)
|
|
|
- * 说明:50ms 快速重试,给连接重建预留时间
|
|
|
- */
|
|
|
- private static final long RETRY_DELAY_MS = 10;
|
|
|
-
|
|
|
/**
|
|
|
* 单次 gRPC 请求的拆包大小(按 key 数量)
|
|
|
*
|
|
|
@@ -190,51 +178,15 @@ public class FeatureV2Client {
|
|
|
String description = e.getStatus().getDescription();
|
|
|
|
|
|
// 记录详细的错误信息(使用 error 级别确保一定会输出)
|
|
|
- log.error("gRPC call failed: code={}, description={}, attempt={}/{}, protos.size={}, exception={}",
|
|
|
- code, description, attemptCount + 1, MAX_RETRY_ATTEMPTS + 1, protos.size(), e.getClass().getName(), e);
|
|
|
-
|
|
|
- // 判断是否应该重试
|
|
|
- if (shouldRetry(code) && attemptCount < MAX_RETRY_ATTEMPTS) {
|
|
|
- log.warn("Retrying gRPC call after {}ms, attempt={}/{}, reason={}", RETRY_DELAY_MS, attemptCount + 1, MAX_RETRY_ATTEMPTS, code);
|
|
|
-
|
|
|
- // 等待一段时间后重试(给连接重建预留时间)
|
|
|
- try {
|
|
|
- Thread.sleep(RETRY_DELAY_MS);
|
|
|
- } catch (InterruptedException ie) {
|
|
|
- Thread.currentThread().interrupt();
|
|
|
- log.warn("Retry sleep interrupted", ie);
|
|
|
- }
|
|
|
-
|
|
|
- // 递归调用,进行重试
|
|
|
- return multiGetFeatureWithRetry(protos, attemptCount + 1);
|
|
|
- }
|
|
|
-
|
|
|
- // 重试失败或不可重试的错误,降级返回空结果
|
|
|
- log.error("gRPC call failed after {} attempts, returning empty result for graceful degradation. code={}",
|
|
|
- attemptCount + 1, code);
|
|
|
+ log.error("gRPC call failed: code={}, description={}, protos.size={}, exception={}",
|
|
|
+ code, description, protos.size(), e.getClass().getName(), e);
|
|
|
return Collections.emptyMap();
|
|
|
} catch (Exception e) {
|
|
|
// 捕获所有其他异常(不应该发生,但为了安全起见)
|
|
|
- log.error("multiGetFeatureWithRetry: unexpected exception, attempt={}/{}, protos.size={}, exception={}",
|
|
|
- attemptCount + 1, MAX_RETRY_ATTEMPTS + 1, protos.size(), e.getClass().getName(), e);
|
|
|
+ log.error("multiGetFeatureWithRetry: unexpected exception, protos.size={}, exception={}",
|
|
|
+ attemptCount + 1, protos.size(), e.getClass().getName(), e);
|
|
|
return Collections.emptyMap();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * 判断错误是否应该重试
|
|
|
- *
|
|
|
- * @param code gRPC 状态码
|
|
|
- * @return true 表示应该重试,false 表示不应该重试
|
|
|
- */
|
|
|
- private boolean shouldRetry(Status.Code code) {
|
|
|
- // UNAVAILABLE: 连接不可用(如网络断开、连接关闭)- 应该重试
|
|
|
- // DEADLINE_EXCEEDED: 超时 - 应该重试
|
|
|
- // RESOURCE_EXHAUSTED: 资源耗尽(如连接池满)- 应该重试
|
|
|
- // CANCELLED: 请求被取消(如服务端处理失败、连接中断)- 应该重试
|
|
|
- return code == Status.Code.UNAVAILABLE
|
|
|
- || code == Status.Code.DEADLINE_EXCEEDED
|
|
|
- || code == Status.Code.RESOURCE_EXHAUSTED
|
|
|
- || code == Status.Code.CANCELLED;
|
|
|
- }
|
|
|
}
|