diff --git a/CHANGELOG.md b/CHANGELOG.md
index b2f545ca6..b5a2e141c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,3 +17,4 @@
- [feat: support custom quickstart circuitbreak delay time.](https://github.com/Tencent/spring-cloud-tencent/pull/1688)
- [feat: add delay interface in tsf-example.](https://github.com/Tencent/spring-cloud-tencent/pull/1689)
- [fix: fix lb configuration on bootstrap step.](https://github.com/Tencent/spring-cloud-tencent/issues/1690)
+- [feat:support fault injection.](https://github.com/Tencent/spring-cloud-tencent/pull/1691)
diff --git a/spring-cloud-starter-tencent-all/pom.xml b/spring-cloud-starter-tencent-all/pom.xml
index c5caacc5a..975f99bd9 100644
--- a/spring-cloud-starter-tencent-all/pom.xml
+++ b/spring-cloud-starter-tencent-all/pom.xml
@@ -79,5 +79,10 @@
com.tencent.cloud
spring-cloud-starter-tencent-traffic-mirroring-plugin
+
+
+ com.tencent.cloud
+ spring-cloud-starter-tencent-fault-injection-plugin
+
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerTest.java
index a7cf3fa97..6e3f66704 100644
--- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerTest.java
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerTest.java
@@ -28,6 +28,7 @@ import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerAuto
import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerFeignClientAutoConfiguration;
import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementAutoConfiguration;
+import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementPropertiesAutoConfiguration;
import com.tencent.polaris.client.util.Utils;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
@@ -57,6 +58,7 @@ public class PolarisCircuitBreakerTest {
private static ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(
PolarisContextAutoConfiguration.class,
+ RpcEnhancementPropertiesAutoConfiguration.class,
RpcEnhancementAutoConfiguration.class,
LoadBalancerAutoConfiguration.class,
PolarisCircuitBreakerFeignClientAutoConfiguration.class,
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerAutoConfigurationTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerAutoConfigurationTest.java
index 456020e78..ac77c52d7 100644
--- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerAutoConfigurationTest.java
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerAutoConfigurationTest.java
@@ -20,6 +20,7 @@ package com.tencent.cloud.polaris.circuitbreaker.config;
import com.tencent.cloud.polaris.circuitbreaker.common.CircuitBreakerConfigModifier;
import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementAutoConfiguration;
+import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementPropertiesAutoConfiguration;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
@@ -39,6 +40,7 @@ public class PolarisCircuitBreakerAutoConfigurationTest {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(
PolarisContextAutoConfiguration.class,
+ RpcEnhancementPropertiesAutoConfiguration.class,
RpcEnhancementAutoConfiguration.class,
LoadBalancerAutoConfiguration.class,
PolarisCircuitBreakerFeignClientAutoConfiguration.class,
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerBootstrapConfigurationTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerBootstrapConfigurationTest.java
index 07e482ca7..41b7315f3 100644
--- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerBootstrapConfigurationTest.java
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerBootstrapConfigurationTest.java
@@ -20,6 +20,7 @@ package com.tencent.cloud.polaris.circuitbreaker.config;
import com.tencent.cloud.polaris.context.PolarisSDKContextManager;
import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementAutoConfiguration;
+import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementPropertiesAutoConfiguration;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
@@ -38,6 +39,7 @@ public class PolarisCircuitBreakerBootstrapConfigurationTest {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(
PolarisContextAutoConfiguration.class,
+ RpcEnhancementPropertiesAutoConfiguration.class,
RpcEnhancementAutoConfiguration.class,
LoadBalancerAutoConfiguration.class,
PolarisCircuitBreakerBootstrapConfiguration.class))
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/endpoint/PolarisCircuitBreakerEndpointAutoConfigurationTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/endpoint/PolarisCircuitBreakerEndpointAutoConfigurationTest.java
index 5e4042704..1937f6842 100644
--- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/endpoint/PolarisCircuitBreakerEndpointAutoConfigurationTest.java
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/endpoint/PolarisCircuitBreakerEndpointAutoConfigurationTest.java
@@ -20,6 +20,7 @@ package com.tencent.cloud.polaris.circuitbreaker.endpoint;
import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerAutoConfiguration;
import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementAutoConfiguration;
+import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementPropertiesAutoConfiguration;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
@@ -37,6 +38,7 @@ public class PolarisCircuitBreakerEndpointAutoConfigurationTest {
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(
PolarisContextAutoConfiguration.class,
+ RpcEnhancementPropertiesAutoConfiguration.class,
RpcEnhancementAutoConfiguration.class,
PolarisCircuitBreakerAutoConfiguration.class,
PolarisCircuitBreakerEndpointAutoConfiguration.class
diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/RouterBootstrapAutoConfigurationTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/RouterBootstrapAutoConfigurationTest.java
index 189d527ec..c49cd0de7 100644
--- a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/RouterBootstrapAutoConfigurationTest.java
+++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/RouterBootstrapAutoConfigurationTest.java
@@ -21,6 +21,7 @@ import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration;
import com.tencent.cloud.polaris.router.RouterConfigModifier;
import com.tencent.cloud.polaris.router.config.properties.PolarisNearByRouterProperties;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementAutoConfiguration;
+import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementPropertiesAutoConfiguration;
import com.tencent.polaris.api.config.Configuration;
import com.tencent.polaris.api.config.consumer.ServiceRouterConfig;
import com.tencent.polaris.factory.ConfigAPIFactory;
@@ -44,6 +45,7 @@ public class RouterBootstrapAutoConfigurationTest {
.withConfiguration(AutoConfigurations.of(
PolarisContextAutoConfiguration.class,
PolarisNearByRouterProperties.class,
+ RpcEnhancementPropertiesAutoConfiguration.class,
RpcEnhancementAutoConfiguration.class,
RouterBootstrapAutoConfiguration.class))
.withPropertyValues("spring.cloud.polaris.enabled=true")
diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/ContextConstant.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/ContextConstant.java
index c9231298f..9a0056185 100644
--- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/ContextConstant.java
+++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/ContextConstant.java
@@ -81,4 +81,11 @@ public final class ContextConstant {
}
}
+
+ public static final class FaultInjection {
+ /**
+ * fault injection fallback http response.
+ */
+ public static final String FAULT_INJECTION_FALLBACK_HTTP_RESPONSE = "FAULT_INJECTION_FALLBACK_HTTP_RESPONSE";
+ }
}
diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/OrderConstant.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/OrderConstant.java
index c6ff02c84..79c2eb027 100644
--- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/OrderConstant.java
+++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/OrderConstant.java
@@ -216,5 +216,10 @@ public class OrderConstant {
* Order of push gateway event reporter modifier.
*/
public static Integer PUSH_GATEWAY_EVENT_ORDER = 2;
+
+ /**
+ * Order of fault injection modifier.
+ */
+ public static Integer FAULT_INJECTION_ORDER = 2;
}
}
diff --git a/spring-cloud-tencent-coverage/pom.xml b/spring-cloud-tencent-coverage/pom.xml
index 8a086a055..689000c07 100644
--- a/spring-cloud-tencent-coverage/pom.xml
+++ b/spring-cloud-tencent-coverage/pom.xml
@@ -100,6 +100,12 @@
spring-cloud-starter-tencent-traffic-mirroring-plugin
${revision}
+
+
+ com.tencent.cloud
+ spring-cloud-starter-tencent-fault-injection-plugin
+ ${revision}
+
diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml
index 64ca4b6f0..053d14568 100644
--- a/spring-cloud-tencent-dependencies/pom.xml
+++ b/spring-cloud-tencent-dependencies/pom.xml
@@ -208,6 +208,12 @@
${revision}
+
+ com.tencent.cloud
+ spring-cloud-starter-tencent-fault-injection-plugin
+ ${revision}
+
+
org.springdoc
diff --git a/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/controller/ConsumerController.java b/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/controller/ConsumerController.java
index fb365be8a..9a2423956 100644
--- a/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/controller/ConsumerController.java
+++ b/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/controller/ConsumerController.java
@@ -30,6 +30,11 @@ import com.tencent.polaris.api.utils.StringUtils;
import com.tencent.polaris.circuitbreak.client.exception.CallAbortedException;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
import org.springframework.tsf.core.TsfContext;
import org.springframework.tsf.core.entity.Tag;
import org.springframework.web.bind.annotation.PathVariable;
@@ -39,6 +44,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.client.HttpClientErrorException;
+import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.RestTemplate;
@RestController
@@ -51,7 +58,7 @@ public class ConsumerController {
private ProviderDemoService providerDemoService;
@RequestMapping(value = "/echo-rest/{str}", method = RequestMethod.GET)
- public String restProvider(@PathVariable String str,
+ public ResponseEntity restProvider(@PathVariable String str,
@RequestParam(required = false) String tagName,
@RequestParam(required = false) String tagValue) {
if (StringUtils.isNotBlank(tagName)) {
@@ -63,10 +70,15 @@ public class ConsumerController {
mTags.put("rest-trace-key2", "value2");
TsfContext.putTags(mTags, Tag.ControlFlag.TRANSITIVE);
try {
- return restTemplate.getForObject("http://provider-demo/echo/" + str, String.class);
+ HttpHeaders headers = new HttpHeaders();
+ HttpEntity entity = new HttpEntity<>(headers);
+ return restTemplate.exchange("http://provider-demo/echo/" + str, HttpMethod.GET, entity, String.class);
}
catch (CallAbortedException callAbortedException) {
- return callAbortedException.getMessage();
+ return new ResponseEntity<>(callAbortedException.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
+ }
+ catch (HttpClientErrorException | HttpServerErrorException httpClientErrorException) {
+ return new ResponseEntity<>(httpClientErrorException.getResponseBodyAsString(), httpClientErrorException.getStatusCode());
}
}
@RequestMapping(value = "/echo-rest/slow/{str}", method = RequestMethod.GET)
diff --git a/spring-cloud-tencent-plugin-starters/pom.xml b/spring-cloud-tencent-plugin-starters/pom.xml
index 9a54eb55f..28f294aa6 100644
--- a/spring-cloud-tencent-plugin-starters/pom.xml
+++ b/spring-cloud-tencent-plugin-starters/pom.xml
@@ -23,6 +23,7 @@
spring-cloud-starter-tencent-fault-tolerance
spring-cloud-starter-tencent-multi-discovery-plugin
spring-cloud-starter-tencent-traffic-mirroring-plugin
+ spring-cloud-starter-tencent-fault-injection-plugin
diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-fault-injection-plugin/pom.xml b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-fault-injection-plugin/pom.xml
new file mode 100644
index 000000000..f01e9ae74
--- /dev/null
+++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-fault-injection-plugin/pom.xml
@@ -0,0 +1,29 @@
+
+
+
+ spring-cloud-tencent-plugin-starters
+ com.tencent.cloud
+ ${revision}
+ ../pom.xml
+
+ 4.0.0
+
+ spring-cloud-starter-tencent-fault-injection-plugin
+ Spring Cloud Starter Tencent Fault Injection Plugin
+
+
+
+ com.tencent.cloud
+ spring-cloud-tencent-rpc-enhancement
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ true
+
+
+
+
\ No newline at end of file
diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-fault-injection-plugin/src/main/java/com/tencent/cloud/plugin/fault/FaultInjectionPrePlugin.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-fault-injection-plugin/src/main/java/com/tencent/cloud/plugin/fault/FaultInjectionPrePlugin.java
new file mode 100644
index 000000000..a02b982bf
--- /dev/null
+++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-fault-injection-plugin/src/main/java/com/tencent/cloud/plugin/fault/FaultInjectionPrePlugin.java
@@ -0,0 +1,118 @@
+/*
+ * Tencent is pleased to support the open source community by making spring-cloud-tencent available.
+ *
+ * Copyright (C) 2021 Tencent. 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.plugin.fault;
+
+import java.util.HashMap;
+
+import com.tencent.cloud.common.constant.ContextConstant;
+import com.tencent.cloud.common.metadata.MetadataContext;
+import com.tencent.cloud.common.metadata.MetadataContextHolder;
+import com.tencent.cloud.plugin.fault.config.FaultInjectionProperties;
+import com.tencent.cloud.plugin.fault.instrument.resttemplate.PolarisFaultInjectionHttpResponse;
+import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin;
+import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
+import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType;
+import com.tencent.cloud.rpc.enhancement.plugin.EnhancedRequestContext;
+import com.tencent.polaris.api.pojo.CircuitBreakerStatus;
+import com.tencent.polaris.api.utils.ClassUtils;
+import com.tencent.polaris.api.utils.StringUtils;
+import com.tencent.polaris.fault.api.core.FaultAPI;
+import com.tencent.polaris.fault.api.rpc.AbortResult;
+import com.tencent.polaris.fault.api.rpc.DelayResult;
+import com.tencent.polaris.fault.api.rpc.FaultRequest;
+import com.tencent.polaris.fault.api.rpc.FaultResponse;
+import com.tencent.polaris.fault.client.exception.FaultInjectionException;
+import com.tencent.polaris.metadata.core.MetadataType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static com.tencent.cloud.common.metadata.MetadataContext.LOCAL_NAMESPACE;
+import static com.tencent.cloud.common.metadata.MetadataContext.LOCAL_SERVICE;
+import static com.tencent.cloud.rpc.enhancement.plugin.PluginOrderConstant.ClientPluginOrder.FAULT_INJECTION_PLUGIN_ORDER;
+
+/**
+ * Fault injection pre plugin.
+ *
+ * @author Haotian Zhang
+ */
+public class FaultInjectionPrePlugin implements EnhancedPlugin {
+
+ private static final Logger LOG = LoggerFactory.getLogger(FaultInjectionPrePlugin.class);
+
+ private final FaultAPI faultAPI;
+
+ private final FaultInjectionProperties faultInjectionProperties;
+
+ public FaultInjectionPrePlugin(FaultAPI faultAPI, FaultInjectionProperties faultInjectionProperties) {
+ this.faultAPI = faultAPI;
+ this.faultInjectionProperties = faultInjectionProperties;
+ }
+
+ @Override
+ public String getName() {
+ return FaultInjectionPrePlugin.class.getName();
+ }
+
+ @Override
+ public EnhancedPluginType getType() {
+ return EnhancedPluginType.Client.PRE;
+ }
+
+ @Override
+ public void run(EnhancedPluginContext context) throws Throwable {
+ if (!faultInjectionProperties.isEnabled()) {
+ return;
+ }
+
+ EnhancedRequestContext request = context.getRequest();
+ String governanceNamespace = StringUtils.isNotEmpty(request.getGovernanceNamespace()) ? request.getGovernanceNamespace() : MetadataContext.LOCAL_NAMESPACE;
+ FaultRequest faultRequest = new FaultRequest(LOCAL_NAMESPACE, LOCAL_SERVICE, governanceNamespace, request.getHost(), MetadataContextHolder.get());
+
+ FaultResponse faultResponse = faultAPI.fault(faultRequest);
+ if (faultResponse.isFaultInjected()) {
+ if (faultResponse.getDelayResult() != null && faultResponse.getDelayResult().getDelay() > 0) {
+ DelayResult delayResult = faultResponse.getDelayResult();
+ Thread.sleep(delayResult.getDelay());
+ }
+ if (faultResponse.getAbortResult() != null) {
+ AbortResult abortResult = faultResponse.getAbortResult();
+ CircuitBreakerStatus.FallbackInfo fallbackInfo = new CircuitBreakerStatus.FallbackInfo(abortResult.getAbortCode(), new HashMap<>(), "");
+ if (ClassUtils.isClassPresent("org.springframework.http.client.ClientHttpResponse")) {
+ Object fallbackResponse = new PolarisFaultInjectionHttpResponse(fallbackInfo);
+ putMetadataObjectValue(ContextConstant.FaultInjection.FAULT_INJECTION_FALLBACK_HTTP_RESPONSE, fallbackResponse);
+ }
+ throw new FaultInjectionException(fallbackInfo);
+ }
+ }
+ }
+
+ private void putMetadataObjectValue(String key, Object value) {
+ MetadataContextHolder.get().getMetadataContainer(MetadataType.APPLICATION, true).
+ putMetadataObjectValue(key, value);
+ }
+
+ @Override
+ public void handlerThrowable(EnhancedPluginContext context, Throwable throwable) {
+ LOG.error("FaultInjectionPrePlugin runs failed. context=[{}].", context, throwable);
+ }
+
+ @Override
+ public int getOrder() {
+ return FAULT_INJECTION_PLUGIN_ORDER;
+ }
+}
diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-fault-injection-plugin/src/main/java/com/tencent/cloud/plugin/fault/config/FaultInjectionAutoConfiguration.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-fault-injection-plugin/src/main/java/com/tencent/cloud/plugin/fault/config/FaultInjectionAutoConfiguration.java
new file mode 100644
index 000000000..32aedb416
--- /dev/null
+++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-fault-injection-plugin/src/main/java/com/tencent/cloud/plugin/fault/config/FaultInjectionAutoConfiguration.java
@@ -0,0 +1,48 @@
+/*
+ * Tencent is pleased to support the open source community by making spring-cloud-tencent available.
+ *
+ * Copyright (C) 2021 Tencent. 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.plugin.fault.config;
+
+import com.tencent.cloud.plugin.fault.FaultInjectionPrePlugin;
+import com.tencent.cloud.polaris.context.PolarisSDKContextManager;
+
+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;
+
+/**
+ * Autoconfiguration for fault injection plugin.
+ *
+ * @author Haotian Zhang
+ */
+@Configuration(proxyBeanMethods = false)
+@ConditionalOnProperty(value = "spring.cloud.polaris.fault-injection.enabled", matchIfMissing = true)
+@EnableConfigurationProperties(FaultInjectionProperties.class)
+public class FaultInjectionAutoConfiguration {
+
+ @Bean
+ public FaultInjectionModifier faultInjectionModifier(FaultInjectionProperties faultInjectionProperties) {
+ return new FaultInjectionModifier(faultInjectionProperties);
+ }
+
+ @Bean
+ public FaultInjectionPrePlugin faultInjectionPrePlugin(PolarisSDKContextManager polarisSDKContextManager,
+ FaultInjectionProperties faultInjectionProperties) {
+ return new FaultInjectionPrePlugin(polarisSDKContextManager.getFaultAPI(), faultInjectionProperties);
+ }
+}
diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-fault-injection-plugin/src/main/java/com/tencent/cloud/plugin/fault/config/FaultInjectionModifier.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-fault-injection-plugin/src/main/java/com/tencent/cloud/plugin/fault/config/FaultInjectionModifier.java
new file mode 100644
index 000000000..07f6fcaaa
--- /dev/null
+++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-fault-injection-plugin/src/main/java/com/tencent/cloud/plugin/fault/config/FaultInjectionModifier.java
@@ -0,0 +1,53 @@
+/*
+ * Tencent is pleased to support the open source community by making spring-cloud-tencent available.
+ *
+ * Copyright (C) 2021 Tencent. 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.plugin.fault.config;
+
+import com.tencent.cloud.common.constant.OrderConstant;
+import com.tencent.cloud.polaris.context.PolarisConfigModifier;
+import com.tencent.polaris.factory.config.ConfigurationImpl;
+import com.tencent.polaris.factory.config.consumer.FaultConfigImpl;
+
+/**
+ * Properties for fault injection.
+ *
+ * @author Haotian Zhang
+ */
+public class FaultInjectionModifier implements PolarisConfigModifier {
+
+ private final FaultInjectionProperties faultInjectionProperties;
+
+ public FaultInjectionModifier(FaultInjectionProperties faultInjectionProperties) {
+ this.faultInjectionProperties = faultInjectionProperties;
+ }
+
+ @Override
+ public void modify(ConfigurationImpl configuration) {
+ FaultConfigImpl faultConfig = (FaultConfigImpl) configuration.getConsumer().getFault();
+ if (faultInjectionProperties.isEnabled()) {
+ faultInjectionProperties.setEnabled(true);
+ }
+ else {
+ faultConfig.setEnable(false);
+ }
+ }
+
+ @Override
+ public int getOrder() {
+ return OrderConstant.Modifier.FAULT_INJECTION_ORDER;
+ }
+}
diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-fault-injection-plugin/src/main/java/com/tencent/cloud/plugin/fault/config/FaultInjectionProperties.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-fault-injection-plugin/src/main/java/com/tencent/cloud/plugin/fault/config/FaultInjectionProperties.java
new file mode 100644
index 000000000..af2af1842
--- /dev/null
+++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-fault-injection-plugin/src/main/java/com/tencent/cloud/plugin/fault/config/FaultInjectionProperties.java
@@ -0,0 +1,49 @@
+/*
+ * Tencent is pleased to support the open source community by making spring-cloud-tencent available.
+ *
+ * Copyright (C) 2021 Tencent. 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.plugin.fault.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * Properties for fault injection.
+ *
+ * @author Haotian Zhang
+ */
+@ConfigurationProperties("spring.cloud.polaris.fault-injection")
+public class FaultInjectionProperties {
+
+ /**
+ * If traffic mirroring is enabled. Default is true.
+ */
+ private boolean enabled = true;
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ @Override
+ public String toString() {
+ return "FaultInjectionProperties{" +
+ "enabled=" + enabled +
+ '}';
+ }
+}
diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-fault-injection-plugin/src/main/java/com/tencent/cloud/plugin/fault/instrument/resttemplate/PolarisFaultInjectionHttpResponse.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-fault-injection-plugin/src/main/java/com/tencent/cloud/plugin/fault/instrument/resttemplate/PolarisFaultInjectionHttpResponse.java
new file mode 100644
index 000000000..c23f0ec13
--- /dev/null
+++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-fault-injection-plugin/src/main/java/com/tencent/cloud/plugin/fault/instrument/resttemplate/PolarisFaultInjectionHttpResponse.java
@@ -0,0 +1,106 @@
+/*
+ * Tencent is pleased to support the open source community by making spring-cloud-tencent available.
+ *
+ * Copyright (C) 2021 Tencent. 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.plugin.fault.instrument.resttemplate;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+
+import com.tencent.polaris.api.pojo.CircuitBreakerStatus;
+import org.jetbrains.annotations.NotNull;
+
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.HttpStatusCode;
+import org.springframework.http.client.ClientHttpResponse;
+
+/**
+ * PolarisFaultInjectionHttpResponse.
+ *
+ * @author Haotian Zhang
+ */
+public class PolarisFaultInjectionHttpResponse implements ClientHttpResponse {
+
+ private final CircuitBreakerStatus.FallbackInfo fallbackInfo;
+
+ private HttpHeaders headers = new HttpHeaders();
+
+ private InputStream body;
+
+ public PolarisFaultInjectionHttpResponse(int code) {
+ this(new CircuitBreakerStatus.FallbackInfo(code, null, null));
+ }
+
+ public PolarisFaultInjectionHttpResponse(int code, String body) {
+ this(new CircuitBreakerStatus.FallbackInfo(code, null, body));
+ }
+
+ public PolarisFaultInjectionHttpResponse(int code, Map headers, String body) {
+ this(new CircuitBreakerStatus.FallbackInfo(code, headers, body));
+ }
+
+ public PolarisFaultInjectionHttpResponse(CircuitBreakerStatus.FallbackInfo fallbackInfo) {
+ this.fallbackInfo = fallbackInfo;
+ if (fallbackInfo.getHeaders() != null) {
+ fallbackInfo.getHeaders().forEach(headers::add);
+ }
+ if (fallbackInfo.getBody() != null) {
+ body = new ByteArrayInputStream(fallbackInfo.getBody().getBytes());
+ }
+ }
+
+ @NotNull
+ @Override
+ public HttpStatusCode getStatusCode() {
+ return HttpStatus.valueOf(fallbackInfo.getCode());
+ }
+
+ @NotNull
+ @Override
+ public final String getStatusText() {
+ HttpStatus status = HttpStatus.resolve(getStatusCode().value());
+ return (status != null ? status.getReasonPhrase() : "");
+ }
+
+ @Override
+ public final void close() {
+ if (this.body != null) {
+ try {
+ this.body.close();
+ }
+ catch (IOException e) {
+ // Ignore exception on close...
+ }
+ }
+ }
+
+ @Override
+ public final InputStream getBody() {
+ return this.body;
+ }
+
+ @Override
+ public final HttpHeaders getHeaders() {
+ return this.headers;
+ }
+
+ public CircuitBreakerStatus.FallbackInfo getFallbackInfo() {
+ return this.fallbackInfo;
+ }
+}
diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-fault-injection-plugin/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-fault-injection-plugin/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 000000000..d79e06104
--- /dev/null
+++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-fault-injection-plugin/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1 @@
+com.tencent.cloud.plugin.fault.config.FaultInjectionAutoConfiguration
diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PolarisSDKContextManager.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PolarisSDKContextManager.java
index 05ab1966f..25538ea70 100644
--- a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PolarisSDKContextManager.java
+++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PolarisSDKContextManager.java
@@ -37,6 +37,8 @@ import com.tencent.polaris.circuitbreak.factory.CircuitBreakAPIFactory;
import com.tencent.polaris.client.api.SDKContext;
import com.tencent.polaris.factory.api.DiscoveryAPIFactory;
import com.tencent.polaris.factory.api.RouterAPIFactory;
+import com.tencent.polaris.fault.api.core.FaultAPI;
+import com.tencent.polaris.fault.factory.FaultAPIFactory;
import com.tencent.polaris.ratelimit.api.core.LimitAPI;
import com.tencent.polaris.ratelimit.factory.LimitAPIFactory;
import com.tencent.polaris.router.api.core.RouterAPI;
@@ -67,6 +69,7 @@ public class PolarisSDKContextManager {
private volatile static CircuitBreakAPI circuitBreakAPI;
private volatile static LimitAPI limitAPI;
private volatile static AuthAPI authAPI;
+ private volatile static FaultAPI faultAPI;
private volatile static AssemblyAPI assemblyAPI;
private final PolarisContextProperties properties;
private final Environment environment;
@@ -126,6 +129,12 @@ public class PolarisSDKContextManager {
authAPI = null;
}
+ // destroy FaultAPI
+ if (Objects.nonNull(faultAPI)) {
+ ((AutoCloseable) faultAPI).close();
+ faultAPI = null;
+ }
+
// destroy AssemblyAPI
if (Objects.nonNull(assemblyAPI)) {
((Destroyable) assemblyAPI).destroy();
@@ -212,6 +221,11 @@ public class PolarisSDKContextManager {
return authAPI;
}
+ public FaultAPI getFaultAPI() {
+ initService();
+ return faultAPI;
+ }
+
public AssemblyAPI getAssemblyAPI() {
return assemblyAPI;
}
@@ -271,6 +285,9 @@ public class PolarisSDKContextManager {
// init AuthAPI
authAPI = AuthAPIFactory.createAuthAPIByContext(serviceSdkContext);
+ // init FaultAPI
+ faultAPI = FaultAPIFactory.createFaultAPIByContext(serviceSdkContext);
+
// init AssemblyAPI
assemblyAPI = AssemblyAPIFactory.createAssemblyAPIByContext(serviceSdkContext);
diff --git a/spring-cloud-tencent-rpc-enhancement/pom.xml b/spring-cloud-tencent-rpc-enhancement/pom.xml
index bc67386be..b7a766f90 100644
--- a/spring-cloud-tencent-rpc-enhancement/pom.xml
+++ b/spring-cloud-tencent-rpc-enhancement/pom.xml
@@ -8,6 +8,18 @@
${revision}
../pom.xml
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 8
+ 8
+
+
+
+
4.0.0
spring-cloud-tencent-rpc-enhancement
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 82a54b4b7..6461cfba3 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
@@ -53,7 +53,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
-import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor;
import org.springframework.cloud.client.loadbalancer.RestTemplateCustomizer;
@@ -84,7 +83,6 @@ import static jakarta.servlet.DispatcherType.REQUEST;
@Configuration(proxyBeanMethods = false)
@ConditionalOnPolarisEnabled
@ConditionalOnProperty(value = "spring.cloud.tencent.rpc-enhancement.enabled", havingValue = "true", matchIfMissing = true)
-@EnableConfigurationProperties(RpcEnhancementReporterProperties.class)
@AutoConfigureAfter(PolarisContextAutoConfiguration.class)
public class RpcEnhancementAutoConfiguration {
@@ -189,6 +187,9 @@ public class RpcEnhancementAutoConfiguration {
@ConditionalOnClass(name = "org.springframework.web.client.RestTemplate")
protected static class PolarisRestTemplateAutoConfiguration {
+ @Autowired(required = false)
+ private List restTemplates = Collections.emptyList();
+
@Bean
@ConditionalOnClass(name = "org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor")
public BlockingLoadBalancerClientBeanPostProcessor loadBalancerInterceptorBeanPostProcessor() {
@@ -202,14 +203,6 @@ public class RpcEnhancementAutoConfiguration {
return new PolarisLoadBalancerRequestTransformer();
}
- @Bean
- @ConditionalOnClass(name = "org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor")
- public BlockingLoadBalancerClientBeanPostProcessor loadBalancerInterceptorBeanPostProcessor() {
- return new BlockingLoadBalancerClientBeanPostProcessor();
- }
- @Autowired(required = false)
- private List restTemplates = Collections.emptyList();
-
@Bean
public EnhancedRestTemplateInterceptor enhancedRestTemplateInterceptor(EnhancedPluginRunner pluginRunner) {
return new EnhancedRestTemplateInterceptor(pluginRunner);
diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementPropertiesAutoConfiguration.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementPropertiesAutoConfiguration.java
new file mode 100644
index 000000000..1f33f81f8
--- /dev/null
+++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementPropertiesAutoConfiguration.java
@@ -0,0 +1,42 @@
+/*
+ * Tencent is pleased to support the open source community by making spring-cloud-tencent available.
+ *
+ * Copyright (C) 2021 Tencent. 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 com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * Auto Configuration for Polaris {@link feign.Feign} OR {@link RestTemplate} which can automatically bring in the call
+ * results for reporting.
+ *
+ * @author Palmer.Xu 2022-06-29
+ */
+@Configuration(proxyBeanMethods = false)
+@ConditionalOnPolarisEnabled
+public class RpcEnhancementPropertiesAutoConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean
+ public RpcEnhancementReporterProperties rpcEnhancementReporterProperties() {
+ return new RpcEnhancementReporterProperties();
+ }
+}
diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementBootstrapConfiguration.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementPropertiesBootstrapConfiguration.java
similarity index 90%
rename from spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementBootstrapConfiguration.java
rename to spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementPropertiesBootstrapConfiguration.java
index 647b094ea..822b69874 100644
--- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementBootstrapConfiguration.java
+++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementPropertiesBootstrapConfiguration.java
@@ -27,6 +27,6 @@ import org.springframework.context.annotation.Import;
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty("spring.cloud.polaris.enabled")
-@Import(RpcEnhancementAutoConfiguration.class)
-public class RpcEnhancementBootstrapConfiguration {
+@Import(RpcEnhancementPropertiesAutoConfiguration.class)
+public class RpcEnhancementPropertiesBootstrapConfiguration {
}
diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/instrument/feign/EnhancedFeignClient.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/instrument/feign/EnhancedFeignClient.java
index 407ddac3a..23fd882cb 100644
--- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/instrument/feign/EnhancedFeignClient.java
+++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/instrument/feign/EnhancedFeignClient.java
@@ -37,6 +37,7 @@ import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext;
import com.tencent.cloud.rpc.enhancement.util.EnhancedPluginUtils;
import com.tencent.polaris.api.pojo.CircuitBreakerStatus;
import com.tencent.polaris.circuitbreak.client.exception.CallAbortedException;
+import com.tencent.polaris.fault.client.exception.FaultInjectionException;
import feign.Client;
import feign.Request;
import feign.Request.Options;
@@ -136,6 +137,33 @@ public class EnhancedFeignClient implements Client {
throw callAbortedException;
}
}
+ catch (FaultInjectionException faultInjectionException) {
+ if (faultInjectionException.getFallbackInfo() != null) {
+ enhancedPluginContext.setDelay(System.currentTimeMillis() - startMillis);
+
+ Response response = getFallbackResponse(faultInjectionException.getFallbackInfo());
+
+ HttpHeaders responseHeaders = new HttpHeaders();
+ response.headers().forEach((s, strings) -> responseHeaders.addAll(s, new ArrayList<>(strings)));
+
+ EnhancedResponseContext enhancedResponseContext = EnhancedResponseContext.builder()
+ .httpStatus(response.status())
+ .httpHeaders(responseHeaders)
+ .build();
+ enhancedPluginContext.setResponse(enhancedResponseContext);
+
+ // Run post enhanced plugins.
+ pluginRunner.run(EnhancedPluginType.Client.POST, enhancedPluginContext);
+ return response;
+ }
+ else {
+ enhancedPluginContext.setDelay(System.currentTimeMillis() - startMillis);
+ enhancedPluginContext.setThrowable(faultInjectionException);
+ // Run exception enhanced feign plugins.
+ pluginRunner.run(EnhancedPluginType.Client.EXCEPTION, enhancedPluginContext);
+ throw faultInjectionException;
+ }
+ }
catch (IOException origin) {
enhancedPluginContext.setDelay(System.currentTimeMillis() - startMillis);
enhancedPluginContext.setThrowable(origin);
diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/instrument/resttemplate/EnhancedRestTemplateBlockingLoadBalancerClientInterceptor.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/instrument/resttemplate/EnhancedRestTemplateBlockingLoadBalancerClientInterceptor.java
index 19506542c..a34874541 100644
--- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/instrument/resttemplate/EnhancedRestTemplateBlockingLoadBalancerClientInterceptor.java
+++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/instrument/resttemplate/EnhancedRestTemplateBlockingLoadBalancerClientInterceptor.java
@@ -32,6 +32,7 @@ import com.tencent.cloud.rpc.enhancement.plugin.EnhancedRequestContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext;
import com.tencent.cloud.rpc.enhancement.util.EnhancedPluginUtils;
import com.tencent.polaris.circuitbreak.client.exception.CallAbortedException;
+import com.tencent.polaris.fault.client.exception.FaultInjectionException;
import com.tencent.polaris.metadata.core.MetadataObjectValue;
import com.tencent.polaris.metadata.core.MetadataType;
@@ -140,6 +141,39 @@ public class EnhancedRestTemplateBlockingLoadBalancerClientInterceptor {
}
throw callAbortedException;
}
+ catch (FaultInjectionException faultInjectionException) {
+ MetadataObjectValue