diff --git a/CHANGELOG.md b/CHANGELOG.md
index 53111bed0..5fd31c88e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,3 +6,4 @@
- [Optimize: add EncodeTransferMedataRestTemplateInterceptor to RestTemplate](https://github.com/Tencent/spring-cloud-tencent/pull/439)
- [Add configurable heartbeat interval support](https://github.com/Tencent/spring-cloud-tencent/pull/443)
- [feat:enhance Feign and RestTemplate and support Polaris monitor.](https://github.com/Tencent/spring-cloud-tencent/pull/446)
+- [Optimize feign & rest-template circuit-breaker logic](https://github.com/Tencent/spring-cloud-tencent/pull/453)
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/pom.xml b/spring-cloud-starter-tencent-polaris-circuitbreaker/pom.xml
index f1c42d41c..20bf4bdf2 100644
--- a/spring-cloud-starter-tencent-polaris-circuitbreaker/pom.xml
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/pom.xml
@@ -18,6 +18,7 @@
com.tencent.cloud
spring-cloud-tencent-polaris-loadbalancer
+
com.tencent.cloud
spring-cloud-tencent-rpc-enhancement
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/AbstractPolarisCircuitBreakAdapter.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/AbstractPolarisCircuitBreakAdapter.java
new file mode 100644
index 000000000..42137fe62
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/AbstractPolarisCircuitBreakAdapter.java
@@ -0,0 +1,92 @@
+/*
+ * Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+
+package com.tencent.cloud.polaris.circuitbreaker;
+
+import java.util.List;
+import java.util.Objects;
+
+import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerProperties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.lang.Nullable;
+
+import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
+
+/**
+ * Abstract Polaris Circuit-Break Adapter .
+ *
+ * @author Elve.Xu 2022-07-11
+ */
+public abstract class AbstractPolarisCircuitBreakAdapter {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractPolarisCircuitBreakAdapter.class);
+
+ protected final PolarisCircuitBreakerProperties properties;
+
+ /**
+ * Constructor With {@link PolarisCircuitBreakerProperties} .
+ *
+ * @param properties instance of {@link PolarisCircuitBreakerProperties}.
+ */
+ protected AbstractPolarisCircuitBreakAdapter(PolarisCircuitBreakerProperties properties) {
+ this.properties = properties;
+ }
+
+ /**
+ * Callback after completion of request processing, Check if business meltdown reporting is required.
+ *
+ * @param httpStatus request http status code
+ * @return true , otherwise return false .
+ */
+ protected boolean apply(@Nullable HttpStatus httpStatus) {
+ if (Objects.isNull(httpStatus)) {
+ return false;
+ }
+ else {
+ // statuses > series
+ List status = properties.getStatuses();
+
+ if (status.isEmpty()) {
+ List series = properties.getSeries();
+ // Check INTERNAL_SERVER_ERROR (500) status.
+ if (properties.getIgnoreInternalServerError() && Objects.equals(httpStatus, INTERNAL_SERVER_ERROR)) {
+ return false;
+ }
+ if (series.isEmpty()) {
+ return false;
+ }
+ else {
+ try {
+ return series.contains(HttpStatus.Series.valueOf(httpStatus));
+ }
+ catch (Exception e) {
+ LOG.warn("Decode http status failed.", e);
+ }
+ }
+ }
+ else {
+ // Use the user-specified fuse status code.
+ return status.contains(httpStatus);
+ }
+ }
+ // DEFAULT RETURN FALSE.
+ return false;
+ }
+}
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerProperties.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerProperties.java
new file mode 100644
index 000000000..a47ad20a7
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerProperties.java
@@ -0,0 +1,113 @@
+/*
+ * Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+
+package com.tencent.cloud.polaris.circuitbreaker.config;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.http.HttpStatus;
+
+import static org.springframework.http.HttpStatus.BAD_GATEWAY;
+import static org.springframework.http.HttpStatus.BANDWIDTH_LIMIT_EXCEEDED;
+import static org.springframework.http.HttpStatus.GATEWAY_TIMEOUT;
+import static org.springframework.http.HttpStatus.HTTP_VERSION_NOT_SUPPORTED;
+import static org.springframework.http.HttpStatus.INSUFFICIENT_STORAGE;
+import static org.springframework.http.HttpStatus.LOOP_DETECTED;
+import static org.springframework.http.HttpStatus.NETWORK_AUTHENTICATION_REQUIRED;
+import static org.springframework.http.HttpStatus.NOT_EXTENDED;
+import static org.springframework.http.HttpStatus.NOT_IMPLEMENTED;
+import static org.springframework.http.HttpStatus.SERVICE_UNAVAILABLE;
+import static org.springframework.http.HttpStatus.VARIANT_ALSO_NEGOTIATES;
+
+/**
+ * Properties of Polaris CircuitBreaker .
+ *
+ * @author Elve.Xu 2022-07-08
+ */
+@ConfigurationProperties("spring.cloud.polaris.circuitbreaker")
+public class PolarisCircuitBreakerProperties {
+
+ /**
+ * If circuit-breaker enabled.
+ */
+ private Boolean enabled = true;
+
+ /**
+ * Specify the Http status code(s) that needs to be fused.
+ */
+ private List statuses = toList(NOT_IMPLEMENTED, BAD_GATEWAY,
+ SERVICE_UNAVAILABLE, GATEWAY_TIMEOUT, HTTP_VERSION_NOT_SUPPORTED, VARIANT_ALSO_NEGOTIATES,
+ INSUFFICIENT_STORAGE, LOOP_DETECTED, BANDWIDTH_LIMIT_EXCEEDED, NOT_EXTENDED, NETWORK_AUTHENTICATION_REQUIRED);
+
+ /**
+ * Specify List of HTTP status series.
+ */
+ private List series = toList(HttpStatus.Series.SERVER_ERROR);
+
+ /**
+ * Ignore Internal Server Error Http Status Code,
+ * Only takes effect if the attribute {@link PolarisCircuitBreakerProperties#series} is not empty.
+ */
+ private Boolean ignoreInternalServerError = true;
+
+ /**
+ * Convert items to List.
+ *
+ * @param items item arrays
+ * @param Object Generics.
+ * @return list
+ */
+ @SafeVarargs
+ private static List toList(T... items) {
+ return new ArrayList<>(Arrays.asList(items));
+ }
+
+ public Boolean getEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(Boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public List getStatuses() {
+ return statuses;
+ }
+
+ public void setStatuses(List statuses) {
+ this.statuses = statuses;
+ }
+
+ public List getSeries() {
+ return series;
+ }
+
+ public void setSeries(List series) {
+ this.series = series;
+ }
+
+ public Boolean getIgnoreInternalServerError() {
+ return ignoreInternalServerError;
+ }
+
+ public void setIgnoreInternalServerError(Boolean ignoreInternalServerError) {
+ this.ignoreInternalServerError = ignoreInternalServerError;
+ }
+}
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/AbstractPolarisCircuitBreakAdapterTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/AbstractPolarisCircuitBreakAdapterTest.java
new file mode 100644
index 000000000..0775c8313
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/AbstractPolarisCircuitBreakAdapterTest.java
@@ -0,0 +1,117 @@
+/*
+ * Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+
+package com.tencent.cloud.polaris.circuitbreaker;
+
+import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerProperties;
+import org.assertj.core.api.Assertions;
+import org.junit.Test;
+
+import org.springframework.http.HttpStatus;
+
+/**
+ * Test For {@link AbstractPolarisCircuitBreakAdapter}.
+ *
+ * @author Elve.Xu
+ * @version ${project.version} - 2022/7/11
+ */
+public class AbstractPolarisCircuitBreakAdapterTest {
+
+ @Test
+ public void testApplyWithDefaultConfig() {
+ PolarisCircuitBreakerProperties properties = new PolarisCircuitBreakerProperties();
+ // Mock Condition
+ SimplePolarisCircuitBreakAdapter adapter = new SimplePolarisCircuitBreakAdapter(properties);
+
+ // Assert
+ Assertions.assertThat(adapter.apply(HttpStatus.OK)).isEqualTo(false);
+ Assertions.assertThat(adapter.apply(HttpStatus.INTERNAL_SERVER_ERROR)).isEqualTo(false);
+ Assertions.assertThat(adapter.apply(HttpStatus.BAD_GATEWAY)).isEqualTo(true);
+ }
+
+ @Test
+ public void testApplyWithoutIgnoreInternalServerError() {
+ PolarisCircuitBreakerProperties properties = new PolarisCircuitBreakerProperties();
+ // Mock Condition
+ properties.getStatuses().clear();
+ properties.setIgnoreInternalServerError(false);
+
+ SimplePolarisCircuitBreakAdapter adapter = new SimplePolarisCircuitBreakAdapter(properties);
+
+ // Assert
+ Assertions.assertThat(adapter.apply(HttpStatus.OK)).isEqualTo(false);
+ Assertions.assertThat(adapter.apply(HttpStatus.INTERNAL_SERVER_ERROR)).isEqualTo(true);
+ Assertions.assertThat(adapter.apply(HttpStatus.BAD_GATEWAY)).isEqualTo(true);
+ }
+
+ @Test
+ public void testApplyWithIgnoreInternalServerError() {
+ PolarisCircuitBreakerProperties properties = new PolarisCircuitBreakerProperties();
+ // Mock Condition
+ properties.getStatuses().clear();
+ properties.setIgnoreInternalServerError(true);
+
+ SimplePolarisCircuitBreakAdapter adapter = new SimplePolarisCircuitBreakAdapter(properties);
+
+ // Assert
+ Assertions.assertThat(adapter.apply(HttpStatus.OK)).isEqualTo(false);
+ Assertions.assertThat(adapter.apply(HttpStatus.INTERNAL_SERVER_ERROR)).isEqualTo(false);
+ Assertions.assertThat(adapter.apply(HttpStatus.BAD_GATEWAY)).isEqualTo(true);
+ }
+
+ @Test
+ public void testApplyWithoutSeries() {
+ PolarisCircuitBreakerProperties properties = new PolarisCircuitBreakerProperties();
+ // Mock Condition
+ properties.getStatuses().clear();
+ properties.getSeries().clear();
+
+ SimplePolarisCircuitBreakAdapter adapter = new SimplePolarisCircuitBreakAdapter(properties);
+
+ // Assert
+ Assertions.assertThat(adapter.apply(HttpStatus.OK)).isEqualTo(false);
+ Assertions.assertThat(adapter.apply(HttpStatus.INTERNAL_SERVER_ERROR)).isEqualTo(false);
+ Assertions.assertThat(adapter.apply(HttpStatus.BAD_GATEWAY)).isEqualTo(false);
+ }
+
+ @Test
+ public void testApplyWithSeries() {
+ PolarisCircuitBreakerProperties properties = new PolarisCircuitBreakerProperties();
+ // Mock Condition
+ properties.getStatuses().clear();
+ properties.getSeries().clear();
+ properties.getSeries().add(HttpStatus.Series.CLIENT_ERROR);
+
+ SimplePolarisCircuitBreakAdapter adapter = new SimplePolarisCircuitBreakAdapter(properties);
+
+ // Assert
+ Assertions.assertThat(adapter.apply(HttpStatus.OK)).isEqualTo(false);
+ Assertions.assertThat(adapter.apply(HttpStatus.INTERNAL_SERVER_ERROR)).isEqualTo(false);
+ Assertions.assertThat(adapter.apply(HttpStatus.BAD_GATEWAY)).isEqualTo(false);
+ Assertions.assertThat(adapter.apply(HttpStatus.FORBIDDEN)).isEqualTo(true);
+ }
+
+ /**
+ * Simple Polaris CircuitBreak Adapter Implements .
+ */
+ public static class SimplePolarisCircuitBreakAdapter extends AbstractPolarisCircuitBreakAdapter {
+
+ public SimplePolarisCircuitBreakAdapter(PolarisCircuitBreakerProperties properties) {
+ super(properties);
+ }
+ }
+}
diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/src/main/resources/bootstrap.yml
index 91a7570cd..a3b008536 100644
--- a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/src/main/resources/bootstrap.yml
+++ b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/src/main/resources/bootstrap.yml
@@ -15,6 +15,12 @@ spring:
port: 28081
loadbalancer:
configurations: polaris
+# tencent:
+# rpc-enhancement:
+# enabled: true
+# ignore-internal-server-error: true
+# series: server_error
+# statuses: gateway_timeout, bad_gateway, service_unavailable
feign:
circuitbreaker:
enabled: true
diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/AbstractPolarisReporterAdapter.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/AbstractPolarisReporterAdapter.java
new file mode 100644
index 000000000..41b9fe154
--- /dev/null
+++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/AbstractPolarisReporterAdapter.java
@@ -0,0 +1,121 @@
+/*
+ * Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+
+package com.tencent.cloud.rpc.enhancement;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementProperties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.lang.Nullable;
+
+import static org.springframework.http.HttpStatus.BAD_GATEWAY;
+import static org.springframework.http.HttpStatus.BANDWIDTH_LIMIT_EXCEEDED;
+import static org.springframework.http.HttpStatus.GATEWAY_TIMEOUT;
+import static org.springframework.http.HttpStatus.HTTP_VERSION_NOT_SUPPORTED;
+import static org.springframework.http.HttpStatus.INSUFFICIENT_STORAGE;
+import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
+import static org.springframework.http.HttpStatus.LOOP_DETECTED;
+import static org.springframework.http.HttpStatus.NETWORK_AUTHENTICATION_REQUIRED;
+import static org.springframework.http.HttpStatus.NOT_EXTENDED;
+import static org.springframework.http.HttpStatus.NOT_IMPLEMENTED;
+import static org.springframework.http.HttpStatus.SERVICE_UNAVAILABLE;
+import static org.springframework.http.HttpStatus.VARIANT_ALSO_NEGOTIATES;
+
+/**
+ * Abstract Polaris Reporter Adapter .
+ *
+ * @author Elve.Xu 2022-07-11
+ */
+public abstract class AbstractPolarisReporterAdapter {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractPolarisReporterAdapter.class);
+
+ protected final RpcEnhancementProperties properties;
+
+ private static final List HTTP_STATUSES = toList(NOT_IMPLEMENTED, BAD_GATEWAY,
+ SERVICE_UNAVAILABLE, GATEWAY_TIMEOUT, HTTP_VERSION_NOT_SUPPORTED, VARIANT_ALSO_NEGOTIATES,
+ INSUFFICIENT_STORAGE, LOOP_DETECTED, BANDWIDTH_LIMIT_EXCEEDED, NOT_EXTENDED, NETWORK_AUTHENTICATION_REQUIRED);
+
+ /**
+ * Constructor With {@link RpcEnhancementProperties} .
+ *
+ * @param properties instance of {@link RpcEnhancementProperties}.
+ */
+ protected AbstractPolarisReporterAdapter(RpcEnhancementProperties properties) {
+ this.properties = properties;
+ }
+
+ /**
+ * Convert items to List.
+ *
+ * @param items item arrays
+ * @param Object Generics.
+ * @return list
+ */
+ @SafeVarargs
+ private static List toList(T... items) {
+ return new ArrayList<>(Arrays.asList(items));
+ }
+
+ /**
+ * Callback after completion of request processing, Check if business meltdown reporting is required.
+ *
+ * @param httpStatus request http status code
+ * @return true , otherwise return false .
+ */
+ protected boolean apply(@Nullable HttpStatus httpStatus) {
+ if (Objects.isNull(httpStatus)) {
+ return false;
+ }
+ else {
+ // statuses > series
+ List status = properties.getStatuses();
+
+ if (status.isEmpty()) {
+ List series = properties.getSeries();
+ // Check INTERNAL_SERVER_ERROR (500) status.
+ if (properties.isIgnoreInternalServerError() && Objects.equals(httpStatus, INTERNAL_SERVER_ERROR)) {
+ return false;
+ }
+ if (series.isEmpty()) {
+ return HTTP_STATUSES.contains(httpStatus);
+ }
+ else {
+ try {
+ return series.contains(HttpStatus.Series.valueOf(httpStatus));
+ }
+ catch (Exception e) {
+ LOG.warn("Decode http status failed.", e);
+ }
+ }
+ }
+ else {
+ // Use the user-specified fuse status code.
+ return status.contains(httpStatus);
+ }
+ }
+ // DEFAULT RETURN FALSE.
+ return false;
+ }
+}
diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementAutoConfiguration.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementAutoConfiguration.java
index b44400a33..4dc25c30b 100644
--- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementAutoConfiguration.java
+++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementAutoConfiguration.java
@@ -34,6 +34,7 @@ import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
@@ -49,6 +50,7 @@ import static org.springframework.core.Ordered.HIGHEST_PRECEDENCE;
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(value = "spring.cloud.tencent.rpc-enhancement.enabled", havingValue = "true", matchIfMissing = true)
+@EnableConfigurationProperties(RpcEnhancementProperties.class)
@AutoConfigureAfter(PolarisContextAutoConfiguration.class)
public class RpcEnhancementAutoConfiguration {
@@ -74,8 +76,8 @@ public class RpcEnhancementAutoConfiguration {
static class PolarisReporterConfig {
@Bean
- public SuccessPolarisReporter successPolarisReporter() {
- return new SuccessPolarisReporter();
+ public SuccessPolarisReporter successPolarisReporter(RpcEnhancementProperties properties) {
+ return new SuccessPolarisReporter(properties);
}
@Bean
@@ -97,8 +99,9 @@ public class RpcEnhancementAutoConfiguration {
@Bean
public EnhancedRestTemplateReporter polarisRestTemplateResponseErrorHandler(
- ConsumerAPI consumerAPI, @Autowired(required = false) PolarisResponseErrorHandler polarisResponseErrorHandler) {
- return new EnhancedRestTemplateReporter(consumerAPI, polarisResponseErrorHandler);
+ RpcEnhancementProperties properties, ConsumerAPI consumerAPI,
+ @Autowired(required = false) PolarisResponseErrorHandler polarisResponseErrorHandler) {
+ return new EnhancedRestTemplateReporter(properties, consumerAPI, polarisResponseErrorHandler);
}
@Bean
diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementProperties.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementProperties.java
new file mode 100644
index 000000000..612a97fbe
--- /dev/null
+++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementProperties.java
@@ -0,0 +1,99 @@
+/*
+ * Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+
+package com.tencent.cloud.rpc.enhancement.config;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.http.HttpStatus;
+
+/**
+ * Properties of Polaris CircuitBreaker .
+ *
+ * @author Elve.Xu 2022-07-08
+ */
+@ConfigurationProperties("spring.cloud.tencent.rpc-enhancement")
+public class RpcEnhancementProperties {
+
+ /**
+ * If circuit-breaker enabled.
+ */
+ private boolean enabled = true;
+
+ /**
+ * Specify the Http status code(s) that needs to be fused.
+ */
+ private List statuses = new ArrayList<>();
+
+ /**
+ * Specify List of HTTP status series.
+ */
+ private List series = toList(HttpStatus.Series.SERVER_ERROR);
+
+ /**
+ * Ignore Internal Server Error Http Status Code,
+ * Only takes effect if the attribute {@link RpcEnhancementProperties#series} is not empty.
+ */
+ private boolean ignoreInternalServerError = true;
+
+ /**
+ * Convert items to List.
+ *
+ * @param items item arrays
+ * @param Object Generics.
+ * @return list
+ */
+ @SafeVarargs
+ private static List toList(T... items) {
+ return new ArrayList<>(Arrays.asList(items));
+ }
+
+ public List getStatuses() {
+ return statuses;
+ }
+
+ public void setStatuses(List statuses) {
+ this.statuses = statuses;
+ }
+
+ public List getSeries() {
+ return series;
+ }
+
+ public void setSeries(List series) {
+ this.series = series;
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public boolean isIgnoreInternalServerError() {
+ return ignoreInternalServerError;
+ }
+
+ public void setIgnoreInternalServerError(boolean ignoreInternalServerError) {
+ this.ignoreInternalServerError = ignoreInternalServerError;
+ }
+}
diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/plugin/reporter/SuccessPolarisReporter.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/plugin/reporter/SuccessPolarisReporter.java
index 332711eab..e2bb22b32 100644
--- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/plugin/reporter/SuccessPolarisReporter.java
+++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/plugin/reporter/SuccessPolarisReporter.java
@@ -17,6 +17,8 @@
package com.tencent.cloud.rpc.enhancement.feign.plugin.reporter;
+import com.tencent.cloud.rpc.enhancement.AbstractPolarisReporterAdapter;
+import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementProperties;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignContext;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPlugin;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPluginType;
@@ -30,16 +32,21 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
+import org.springframework.http.HttpStatus;
/**
* Polaris reporter when feign call is successful.
*
* @author Haotian Zhang
*/
-public class SuccessPolarisReporter implements EnhancedFeignPlugin {
+public class SuccessPolarisReporter extends AbstractPolarisReporterAdapter implements EnhancedFeignPlugin {
private static final Logger LOG = LoggerFactory.getLogger(SuccessPolarisReporter.class);
+ public SuccessPolarisReporter(RpcEnhancementProperties properties) {
+ super(properties);
+ }
+
@Autowired(required = false)
private ConsumerAPI consumerAPI;
@@ -59,7 +66,7 @@ public class SuccessPolarisReporter implements EnhancedFeignPlugin {
Request request = context.getRequest();
Response response = context.getResponse();
RetStatus retStatus = RetStatus.RetSuccess;
- if (response.status() > 500) {
+ if (apply(HttpStatus.resolve(response.status()))) {
retStatus = RetStatus.RetFail;
}
LOG.debug("Will report result of {}. Request=[{}]. Response=[{}].", retStatus.name(), request, response);
diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateReporter.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateReporter.java
index 7618793a9..dd841b4b6 100644
--- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateReporter.java
+++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateReporter.java
@@ -25,6 +25,8 @@ import java.util.Objects;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.util.ReflectionUtils;
+import com.tencent.cloud.rpc.enhancement.AbstractPolarisReporterAdapter;
+import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementProperties;
import com.tencent.polaris.api.core.ConsumerAPI;
import com.tencent.polaris.api.pojo.RetStatus;
import com.tencent.polaris.api.pojo.ServiceKey;
@@ -43,7 +45,7 @@ import org.springframework.web.client.ResponseErrorHandler;
*
* @author wh 2022/6/21
*/
-public class EnhancedRestTemplateReporter implements ResponseErrorHandler {
+public class EnhancedRestTemplateReporter extends AbstractPolarisReporterAdapter implements ResponseErrorHandler {
private static final Logger LOG = LoggerFactory.getLogger(EnhancedRestTemplateReporter.class);
@@ -53,8 +55,9 @@ public class EnhancedRestTemplateReporter implements ResponseErrorHandler {
private final PolarisResponseErrorHandler polarisResponseErrorHandler;
- public EnhancedRestTemplateReporter(
- ConsumerAPI consumerAPI, PolarisResponseErrorHandler polarisResponseErrorHandler) {
+ public EnhancedRestTemplateReporter(RpcEnhancementProperties properties, ConsumerAPI consumerAPI,
+ PolarisResponseErrorHandler polarisResponseErrorHandler) {
+ super(properties);
this.consumerAPI = consumerAPI;
this.polarisResponseErrorHandler = polarisResponseErrorHandler;
}
@@ -85,7 +88,7 @@ public class EnhancedRestTemplateReporter implements ResponseErrorHandler {
resultRequest.setPort(realURL.getPort());
}
- if (response.getStatusCode().value() > 500) {
+ if (apply(response.getStatusCode())) {
resultRequest.setRetStatus(RetStatus.RetFail);
}
}
diff --git a/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/AbstractPolarisReporterAdapterTest.java b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/AbstractPolarisReporterAdapterTest.java
new file mode 100644
index 000000000..db205c313
--- /dev/null
+++ b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/AbstractPolarisReporterAdapterTest.java
@@ -0,0 +1,116 @@
+/*
+ * Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+
+package com.tencent.cloud.rpc.enhancement;
+
+import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementProperties;
+import org.assertj.core.api.Assertions;
+import org.junit.Test;
+
+import org.springframework.http.HttpStatus;
+
+/**
+ * Test For {@link AbstractPolarisReporterAdapter}.
+ *
+ * @author Elve.Xu 2022/7/11
+ */
+public class AbstractPolarisReporterAdapterTest {
+
+ @Test
+ public void testApplyWithDefaultConfig() {
+ RpcEnhancementProperties properties = new RpcEnhancementProperties();
+ // Mock Condition
+ SimplePolarisReporterAdapter adapter = new SimplePolarisReporterAdapter(properties);
+
+ // Assert
+ Assertions.assertThat(adapter.apply(HttpStatus.OK)).isEqualTo(false);
+ Assertions.assertThat(adapter.apply(HttpStatus.INTERNAL_SERVER_ERROR)).isEqualTo(false);
+ Assertions.assertThat(adapter.apply(HttpStatus.BAD_GATEWAY)).isEqualTo(true);
+ }
+
+ @Test
+ public void testApplyWithoutIgnoreInternalServerError() {
+ RpcEnhancementProperties properties = new RpcEnhancementProperties();
+ // Mock Condition
+ properties.getStatuses().clear();
+ properties.setIgnoreInternalServerError(false);
+
+ SimplePolarisReporterAdapter adapter = new SimplePolarisReporterAdapter(properties);
+
+ // Assert
+ Assertions.assertThat(adapter.apply(HttpStatus.OK)).isEqualTo(false);
+ Assertions.assertThat(adapter.apply(HttpStatus.INTERNAL_SERVER_ERROR)).isEqualTo(true);
+ Assertions.assertThat(adapter.apply(HttpStatus.BAD_GATEWAY)).isEqualTo(true);
+ }
+
+ @Test
+ public void testApplyWithIgnoreInternalServerError() {
+ RpcEnhancementProperties properties = new RpcEnhancementProperties();
+ // Mock Condition
+ properties.getStatuses().clear();
+ properties.setIgnoreInternalServerError(true);
+
+ SimplePolarisReporterAdapter adapter = new SimplePolarisReporterAdapter(properties);
+
+ // Assert
+ Assertions.assertThat(adapter.apply(HttpStatus.OK)).isEqualTo(false);
+ Assertions.assertThat(adapter.apply(HttpStatus.INTERNAL_SERVER_ERROR)).isEqualTo(false);
+ Assertions.assertThat(adapter.apply(HttpStatus.BAD_GATEWAY)).isEqualTo(true);
+ }
+
+ @Test
+ public void testApplyWithoutSeries() {
+ RpcEnhancementProperties properties = new RpcEnhancementProperties();
+ // Mock Condition
+ properties.getStatuses().clear();
+ properties.getSeries().clear();
+
+ SimplePolarisReporterAdapter adapter = new SimplePolarisReporterAdapter(properties);
+
+ // Assert
+ Assertions.assertThat(adapter.apply(HttpStatus.OK)).isEqualTo(false);
+ Assertions.assertThat(adapter.apply(HttpStatus.INTERNAL_SERVER_ERROR)).isEqualTo(false);
+ Assertions.assertThat(adapter.apply(HttpStatus.BAD_GATEWAY)).isEqualTo(true);
+ }
+
+ @Test
+ public void testApplyWithSeries() {
+ RpcEnhancementProperties properties = new RpcEnhancementProperties();
+ // Mock Condition
+ properties.getStatuses().clear();
+ properties.getSeries().clear();
+ properties.getSeries().add(HttpStatus.Series.CLIENT_ERROR);
+
+ SimplePolarisReporterAdapter adapter = new SimplePolarisReporterAdapter(properties);
+
+ // Assert
+ Assertions.assertThat(adapter.apply(HttpStatus.OK)).isEqualTo(false);
+ Assertions.assertThat(adapter.apply(HttpStatus.INTERNAL_SERVER_ERROR)).isEqualTo(false);
+ Assertions.assertThat(adapter.apply(HttpStatus.BAD_GATEWAY)).isEqualTo(false);
+ Assertions.assertThat(adapter.apply(HttpStatus.FORBIDDEN)).isEqualTo(true);
+ }
+
+ /**
+ * Simple Polaris CircuitBreak Adapter Implements .
+ */
+ public static class SimplePolarisReporterAdapter extends AbstractPolarisReporterAdapter {
+
+ public SimplePolarisReporterAdapter(RpcEnhancementProperties properties) {
+ super(properties);
+ }
+ }
+}
diff --git a/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/feign/plugin/reporter/SuccessPolarisReporterTest.java b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/feign/plugin/reporter/SuccessPolarisReporterTest.java
index cdcc594f2..b3e28a5ca 100644
--- a/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/feign/plugin/reporter/SuccessPolarisReporterTest.java
+++ b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/feign/plugin/reporter/SuccessPolarisReporterTest.java
@@ -43,7 +43,7 @@ import static org.mockito.Mockito.mock;
*
* @author Haotian Zhang
*/
-@RunWith(MockitoJUnitRunner.class)
+@RunWith(MockitoJUnitRunner.Silent.class)
public class SuccessPolarisReporterTest {
private static MockedStatic mockedReporterUtils;
diff --git a/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateReporterTest.java b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateReporterTest.java
index 53e7ef652..631155b8f 100644
--- a/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateReporterTest.java
+++ b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateReporterTest.java
@@ -22,6 +22,7 @@ import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
+import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementProperties;
import com.tencent.polaris.api.core.ConsumerAPI;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -47,7 +48,8 @@ public class EnhancedRestTemplateReporterTest {
@Test
public void handleError() throws Exception {
ConsumerAPI consumerAPI = mock(ConsumerAPI.class);
- EnhancedRestTemplateReporter enhancedRestTemplateReporter = new EnhancedRestTemplateReporter(consumerAPI, null);
+ EnhancedRestTemplateReporter enhancedRestTemplateReporter =
+ new EnhancedRestTemplateReporter(mock(RpcEnhancementProperties.class), consumerAPI, null);
URI uri = mock(URI.class);
when(uri.getPath()).thenReturn("/test");
when(uri.getHost()).thenReturn("host");