diff --git a/CHANGELOG.md b/CHANGELOG.md
index c1f85bb12..3ba2c8459 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,7 +8,8 @@
- [fix:fix the error capture of rate limit exception.](https://github.com/Tencent/spring-cloud-tencent/pull/854)
- [feature:add User-Agent:polaris for healthyCheck api.](https://github.com/Tencent/spring-cloud-tencent/pull/859)
- [feat:enable stat reporting as default.](https://github.com/Tencent/spring-cloud-tencent/pull/862)
-- [optimize:optimize ServiceRuleManager.](https://github.com/Tencent/spring-cloud-tencent/pull/869)
- [refactor:update to junit 5.](https://github.com/Tencent/spring-cloud-tencent/pull/865)
+- [optimize:optimize ServiceRuleManager.](https://github.com/Tencent/spring-cloud-tencent/pull/869)
- [docs:support auto snapshot release in GitHub Action.](https://github.com/Tencent/spring-cloud-tencent/pull/868)
+- [feature:add polaris circuit breaker support.](https://github.com/Tencent/spring-cloud-tencent/pull/875)
- [refactor:refactor stat module.](https://github.com/Tencent/spring-cloud-tencent/pull/876)
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/pom.xml b/spring-cloud-starter-tencent-polaris-circuitbreaker/pom.xml
index dce497bd1..6ce29236c 100644
--- a/spring-cloud-starter-tencent-polaris-circuitbreaker/pom.xml
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/pom.xml
@@ -14,6 +14,30 @@
+
+ org.springframework.boot
+ spring-boot-starter-web
+ true
+
+
+
+ org.springframework.boot
+ spring-boot-starter-webflux
+ true
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-openfeign
+ true
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-gateway
+ true
+
+
com.tencent.cloud
spring-cloud-tencent-rpc-enhancement
@@ -55,6 +79,7 @@
+
@@ -62,5 +87,35 @@
spring-boot-starter-test
test
+
+
+ org.springframework.cloud
+ spring-cloud-starter-contract-stub-runner
+ test
+
+
+
+ com.tencent.polaris
+ polaris-test-common
+ test
+
+
+
+ com.tencent.polaris
+ polaris-test-mock-discovery
+ test
+
+
+
+ org.mockito
+ mockito-inline
+ test
+
+
+
+ io.projectreactor
+ reactor-test
+ test
+
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreaker.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreaker.java
new file mode 100644
index 000000000..d1d70b9e3
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreaker.java
@@ -0,0 +1,68 @@
+/*
+ * 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.function.Function;
+import java.util.function.Supplier;
+
+import com.tencent.cloud.polaris.circuitbreaker.common.PolarisCircuitBreakerConfigBuilder;
+import com.tencent.cloud.polaris.circuitbreaker.common.PolarisResultToErrorCode;
+import com.tencent.polaris.api.pojo.ServiceKey;
+import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI;
+import com.tencent.polaris.circuitbreak.api.FunctionalDecorator;
+import com.tencent.polaris.circuitbreak.api.pojo.FunctionalDecoratorRequest;
+import com.tencent.polaris.circuitbreak.client.exception.CallAbortedException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.springframework.cloud.client.circuitbreaker.CircuitBreaker;
+
+/**
+ * PolarisCircuitBreaker.
+ *
+ * @author seanyu 2023-02-27
+ */
+public class PolarisCircuitBreaker implements CircuitBreaker {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(PolarisCircuitBreaker.class);
+
+ private final FunctionalDecorator decorator;
+
+ public PolarisCircuitBreaker(PolarisCircuitBreakerConfigBuilder.PolarisCircuitBreakerConfiguration conf, CircuitBreakAPI circuitBreakAPI) {
+ FunctionalDecoratorRequest makeDecoratorRequest = new FunctionalDecoratorRequest(new ServiceKey(conf.getNamespace(), conf.getService()), conf.getMethod());
+ makeDecoratorRequest.setSourceService(new ServiceKey(conf.getSourceNamespace(), conf.getSourceService()));
+ makeDecoratorRequest.setResultToErrorCode(new PolarisResultToErrorCode());
+ this.decorator = circuitBreakAPI.makeFunctionalDecorator(makeDecoratorRequest);
+ }
+
+ @Override
+ public T run(Supplier toRun, Function fallback) {
+ Supplier toRunDecorator = decorator.decorateSupplier(toRun);
+ try {
+ return toRunDecorator.get();
+ }
+ catch (CallAbortedException e) {
+ LOGGER.debug("PolarisCircuitBreaker CallAbortedException: {}", e.getMessage());
+ return fallback.apply(e);
+ }
+ catch (Exception e) {
+ return fallback.apply(e);
+ }
+ }
+
+}
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerFactory.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerFactory.java
new file mode 100644
index 000000000..d80ae90e5
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerFactory.java
@@ -0,0 +1,72 @@
+/*
+ * 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.function.Function;
+
+import com.tencent.cloud.polaris.circuitbreaker.common.PolarisCircuitBreakerConfigBuilder;
+import com.tencent.cloud.polaris.circuitbreaker.util.PolarisCircuitBreakerUtils;
+import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI;
+
+import org.springframework.cloud.client.circuitbreaker.CircuitBreaker;
+import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory;
+
+/**
+ * PolarisCircuitBreakerFactory.
+ *
+ * @author seanyu 2023-02-27
+ */
+public class PolarisCircuitBreakerFactory
+ extends CircuitBreakerFactory {
+
+ private Function defaultConfiguration =
+ id -> {
+ String[] metadata = PolarisCircuitBreakerUtils.resolveCircuitBreakerId(id);
+ return new PolarisCircuitBreakerConfigBuilder()
+ .namespace(metadata[0])
+ .service(metadata[1])
+ .method(metadata[2])
+ .build();
+ };
+
+
+ private final CircuitBreakAPI circuitBreakAPI;
+
+ public PolarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI) {
+ this.circuitBreakAPI = circuitBreakAPI;
+ }
+
+ @Override
+ public CircuitBreaker create(String id) {
+ PolarisCircuitBreakerConfigBuilder.PolarisCircuitBreakerConfiguration conf = getConfigurations()
+ .computeIfAbsent(id, defaultConfiguration);
+ return new PolarisCircuitBreaker(conf, circuitBreakAPI);
+ }
+
+ @Override
+ protected PolarisCircuitBreakerConfigBuilder configBuilder(String id) {
+ String[] metadata = PolarisCircuitBreakerUtils.resolveCircuitBreakerId(id);
+ return new PolarisCircuitBreakerConfigBuilder(metadata[0], metadata[1], metadata[2]);
+ }
+
+ @Override
+ public void configureDefault(Function defaultConfiguration) {
+ this.defaultConfiguration = defaultConfiguration;
+ }
+
+}
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/ReactivePolarisCircuitBreaker.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/ReactivePolarisCircuitBreaker.java
new file mode 100644
index 000000000..cfd7e481a
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/ReactivePolarisCircuitBreaker.java
@@ -0,0 +1,70 @@
+/*
+ * 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.function.Function;
+
+import com.tencent.cloud.polaris.circuitbreaker.common.PolarisCircuitBreakerConfigBuilder;
+import com.tencent.cloud.polaris.circuitbreaker.common.PolarisResultToErrorCode;
+import com.tencent.cloud.polaris.circuitbreaker.reactor.PolarisCircuitBreakerReactorTransformer;
+import com.tencent.polaris.api.pojo.ServiceKey;
+import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI;
+import com.tencent.polaris.circuitbreak.api.InvokeHandler;
+import com.tencent.polaris.circuitbreak.api.pojo.FunctionalDecoratorRequest;
+import com.tencent.polaris.circuitbreak.api.pojo.InvokeContext;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreaker;
+
+/**
+ * ReactivePolarisCircuitBreaker.
+ *
+ * @author seanyu 2023-02-27
+ */
+public class ReactivePolarisCircuitBreaker implements ReactiveCircuitBreaker {
+
+ private final InvokeHandler invokeHandler;
+
+ public ReactivePolarisCircuitBreaker(PolarisCircuitBreakerConfigBuilder.PolarisCircuitBreakerConfiguration conf, CircuitBreakAPI circuitBreakAPI) {
+ InvokeContext.RequestContext requestContext = new FunctionalDecoratorRequest(new ServiceKey(conf.getNamespace(), conf.getService()), conf.getMethod());
+ requestContext.setSourceService(new ServiceKey(conf.getSourceNamespace(), conf.getSourceService()));
+ requestContext.setResultToErrorCode(new PolarisResultToErrorCode());
+ this.invokeHandler = circuitBreakAPI.makeInvokeHandler(requestContext);
+ }
+
+
+ @Override
+ public Mono run(Mono toRun, Function> fallback) {
+ Mono toReturn = toRun.transform(new PolarisCircuitBreakerReactorTransformer<>(invokeHandler));
+ if (fallback != null) {
+ toReturn = toReturn.onErrorResume(fallback);
+ }
+ return toReturn;
+ }
+
+ @Override
+ public Flux run(Flux toRun, Function> fallback) {
+ Flux toReturn = toRun.transform(new PolarisCircuitBreakerReactorTransformer<>(invokeHandler));
+ if (fallback != null) {
+ toReturn = toReturn.onErrorResume(fallback);
+ }
+ return toReturn;
+ }
+
+}
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/ReactivePolarisCircuitBreakerFactory.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/ReactivePolarisCircuitBreakerFactory.java
new file mode 100644
index 000000000..4a481e866
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/ReactivePolarisCircuitBreakerFactory.java
@@ -0,0 +1,73 @@
+/*
+ * 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.function.Function;
+
+import com.tencent.cloud.polaris.circuitbreaker.common.PolarisCircuitBreakerConfigBuilder;
+import com.tencent.cloud.polaris.circuitbreaker.util.PolarisCircuitBreakerUtils;
+import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI;
+
+import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreaker;
+import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreakerFactory;
+
+/**
+ * ReactivePolarisCircuitBreakerFactory.
+ *
+ * @author seanyu 2023-02-27
+ */
+public class ReactivePolarisCircuitBreakerFactory extends
+ ReactiveCircuitBreakerFactory {
+
+ private Function defaultConfiguration =
+ id -> {
+ String[] metadata = PolarisCircuitBreakerUtils.resolveCircuitBreakerId(id);
+ return new PolarisCircuitBreakerConfigBuilder()
+ .namespace(metadata[0])
+ .service(metadata[1])
+ .method(metadata[2])
+ .build();
+ };
+
+ private final CircuitBreakAPI circuitBreakAPI;
+
+ public ReactivePolarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI) {
+ this.circuitBreakAPI = circuitBreakAPI;
+ }
+
+
+ @Override
+ public ReactiveCircuitBreaker create(String id) {
+ PolarisCircuitBreakerConfigBuilder.PolarisCircuitBreakerConfiguration conf = getConfigurations()
+ .computeIfAbsent(id, defaultConfiguration);
+ return new ReactivePolarisCircuitBreaker(conf, circuitBreakAPI);
+ }
+
+ @Override
+ protected PolarisCircuitBreakerConfigBuilder configBuilder(String id) {
+ String[] metadata = PolarisCircuitBreakerUtils.resolveCircuitBreakerId(id);
+ return new PolarisCircuitBreakerConfigBuilder(metadata[0], metadata[1], metadata[2]);
+ }
+
+ @Override
+ public void configureDefault(
+ Function defaultConfiguration) {
+ this.defaultConfiguration = defaultConfiguration;
+ }
+
+}
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/common/CircuitBreakerConfigModifier.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/common/CircuitBreakerConfigModifier.java
new file mode 100644
index 000000000..220d98490
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/common/CircuitBreakerConfigModifier.java
@@ -0,0 +1,62 @@
+/*
+ * 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.common;
+
+import com.tencent.cloud.common.constant.ContextConstant;
+import com.tencent.cloud.polaris.context.PolarisConfigModifier;
+import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
+import com.tencent.polaris.api.config.consumer.ServiceRouterConfig;
+import com.tencent.polaris.factory.config.ConfigurationImpl;
+import com.tencent.polaris.plugins.router.healthy.RecoverRouterConfig;
+
+/**
+ * CircuitBreakerConfigModifier.
+ *
+ * @author seanyu 2023-02-27
+ */
+public class CircuitBreakerConfigModifier implements PolarisConfigModifier {
+
+ private final RpcEnhancementReporterProperties properties;
+
+ public CircuitBreakerConfigModifier(RpcEnhancementReporterProperties properties) {
+ this.properties = properties;
+ }
+
+ @Override
+ public void modify(ConfigurationImpl configuration) {
+ properties.setEnabled(true);
+
+ // Turn on circuitbreaker configuration
+ configuration.getConsumer().getCircuitBreaker().setEnable(true);
+
+ // Set excludeCircuitBreakInstances to true
+ RecoverRouterConfig recoverRouterConfig = configuration.getConsumer().getServiceRouter()
+ .getPluginConfig(ServiceRouterConfig.DEFAULT_ROUTER_RECOVER, RecoverRouterConfig.class);
+
+ recoverRouterConfig.setExcludeCircuitBreakInstances(true);
+
+ // Update modified config to source properties
+ configuration.getConsumer().getServiceRouter()
+ .setPluginConfig(ServiceRouterConfig.DEFAULT_ROUTER_RECOVER, recoverRouterConfig);
+ }
+
+ @Override
+ public int getOrder() {
+ return ContextConstant.ModifierOrder.CIRCUIT_BREAKER_ORDER;
+ }
+}
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/common/PolarisCircuitBreakerConfigBuilder.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/common/PolarisCircuitBreakerConfigBuilder.java
new file mode 100644
index 000000000..733180491
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/common/PolarisCircuitBreakerConfigBuilder.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.polaris.circuitbreaker.common;
+
+import com.tencent.cloud.common.metadata.MetadataContext;
+
+import org.springframework.cloud.client.circuitbreaker.ConfigBuilder;
+
+/**
+ * PolarisCircuitBreakerConfigBuilder.
+ *
+ * @author seanyu 2023-02-27
+ */
+public class PolarisCircuitBreakerConfigBuilder implements ConfigBuilder {
+
+ private String namespace = MetadataContext.LOCAL_NAMESPACE;
+
+ private String service;
+
+ private String method;
+
+ public PolarisCircuitBreakerConfigBuilder() {
+
+ }
+
+ public PolarisCircuitBreakerConfigBuilder(String namespace, String service, String method) {
+ this.namespace = namespace;
+ this.service = service;
+ this.method = method;
+ }
+
+ public PolarisCircuitBreakerConfigBuilder namespace(String namespace) {
+ this.namespace = namespace;
+ return this;
+ }
+
+ public PolarisCircuitBreakerConfigBuilder service(String service) {
+ this.service = service;
+ return this;
+ }
+
+ public PolarisCircuitBreakerConfigBuilder method(String method) {
+ this.method = method;
+ return this;
+ }
+
+ @Override
+ public PolarisCircuitBreakerConfiguration build() {
+ PolarisCircuitBreakerConfiguration conf = new PolarisCircuitBreakerConfiguration();
+ conf.setNamespace(namespace);
+ conf.setService(service);
+ conf.setMethod(method);
+ return conf;
+ }
+
+ public static class PolarisCircuitBreakerConfiguration {
+
+ private final String sourceNamespace = MetadataContext.LOCAL_NAMESPACE;
+
+ private final String sourceService = MetadataContext.LOCAL_SERVICE;
+
+ private String namespace;
+
+ private String service;
+
+ private String method;
+
+ public String getNamespace() {
+ return namespace;
+ }
+
+ public void setNamespace(String namespace) {
+ this.namespace = namespace;
+ }
+
+ public String getService() {
+ return service;
+ }
+
+ public void setService(String service) {
+ this.service = service;
+ }
+
+ public String getMethod() {
+ return method;
+ }
+
+ public void setMethod(String method) {
+ this.method = method;
+ }
+
+ public String getSourceNamespace() {
+ return sourceNamespace;
+ }
+
+ public String getSourceService() {
+ return sourceService;
+ }
+ }
+
+}
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/common/PolarisResultToErrorCode.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/common/PolarisResultToErrorCode.java
new file mode 100644
index 000000000..3d0badf3a
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/common/PolarisResultToErrorCode.java
@@ -0,0 +1,65 @@
+/*
+ * 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.common;
+
+import com.tencent.polaris.circuitbreak.api.pojo.ResultToErrorCode;
+import feign.FeignException;
+
+import org.springframework.web.client.RestClientResponseException;
+import org.springframework.web.reactive.function.client.WebClientResponseException;
+
+/**
+ * PolarisResultToErrorCode.
+ *
+ * @author seanyu 2023-02-27
+ */
+public class PolarisResultToErrorCode implements ResultToErrorCode {
+
+ @Override
+ public int onSuccess(Object value) {
+ return 200;
+ }
+
+ @Override
+ public int onError(Throwable e) {
+ if (checkClassExist("org.springframework.web.client.RestClientResponseException")
+ && e instanceof RestClientResponseException) {
+ return ((RestClientResponseException) e).getRawStatusCode();
+ }
+ else if (checkClassExist("feign.FeignException")
+ && e instanceof FeignException) {
+ return ((FeignException) e).status();
+ }
+ else if (checkClassExist("org.springframework.web.reactive.function.client.WebClientResponseException")
+ && e instanceof WebClientResponseException) {
+ return ((WebClientResponseException) e).getRawStatusCode();
+ }
+ return -1;
+ }
+
+ private boolean checkClassExist(String clazzName) {
+ try {
+ Class.forName(clazzName, false, getClass().getClassLoader());
+ }
+ catch (ClassNotFoundException e) {
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/GatewayPolarisCircuitBreakerAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/GatewayPolarisCircuitBreakerAutoConfiguration.java
new file mode 100644
index 000000000..e97358015
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/GatewayPolarisCircuitBreakerAutoConfiguration.java
@@ -0,0 +1,71 @@
+/*
+ * 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 com.tencent.cloud.polaris.circuitbreaker.ReactivePolarisCircuitBreakerFactory;
+import com.tencent.cloud.polaris.circuitbreaker.gateway.PolarisCircuitBreakerFilterFactory;
+
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreakerFactory;
+import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient;
+import org.springframework.cloud.gateway.config.GatewayAutoConfiguration;
+import org.springframework.cloud.gateway.config.conditional.ConditionalOnEnabledFilter;
+import org.springframework.cloud.gateway.discovery.DiscoveryLocatorProperties;
+import org.springframework.cloud.gateway.filter.factory.FallbackHeadersGatewayFilterFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.reactive.DispatcherHandler;
+
+/**
+ * GatewayPolarisCircuitBreakerAutoConfiguration.
+ *
+ * @author seanyu 2023-02-27
+ */
+@Configuration(proxyBeanMethods = false)
+@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true)
+@AutoConfigureAfter({ReactivePolarisCircuitBreakerAutoConfiguration.class })
+@ConditionalOnClass({ DispatcherHandler.class, ReactivePolarisCircuitBreakerAutoConfiguration.class,
+ ReactiveCircuitBreakerFactory.class, ReactivePolarisCircuitBreakerFactory.class, GatewayAutoConfiguration.class})
+public class GatewayPolarisCircuitBreakerAutoConfiguration {
+
+ @Bean
+ @ConditionalOnBean(ReactiveCircuitBreakerFactory.class)
+ @ConditionalOnEnabledFilter
+ public PolarisCircuitBreakerFilterFactory polarisCircuitBreakerFilterFactory(
+ ReactiveCircuitBreakerFactory reactiveCircuitBreakerFactory,
+ ObjectProvider dispatcherHandler,
+ @Autowired(required = false) ReactiveDiscoveryClient discoveryClient,
+ @Autowired(required = false) DiscoveryLocatorProperties properties
+ ) {
+ return new PolarisCircuitBreakerFilterFactory(reactiveCircuitBreakerFactory, dispatcherHandler, discoveryClient, properties);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnEnabledFilter
+ public FallbackHeadersGatewayFilterFactory fallbackHeadersGatewayFilterFactory() {
+ return new FallbackHeadersGatewayFilterFactory();
+ }
+
+}
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerAutoConfiguration.java
index a245d695a..f838214f2 100644
--- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerAutoConfiguration.java
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerAutoConfiguration.java
@@ -17,20 +17,29 @@
package com.tencent.cloud.polaris.circuitbreaker.config;
-import com.tencent.cloud.common.constant.ContextConstant;
-import com.tencent.cloud.polaris.context.PolarisConfigModifier;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.tencent.cloud.polaris.circuitbreaker.PolarisCircuitBreakerFactory;
+import com.tencent.cloud.polaris.circuitbreaker.common.CircuitBreakerConfigModifier;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementAutoConfiguration;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
-import com.tencent.polaris.api.config.consumer.ServiceRouterConfig;
-import com.tencent.polaris.factory.config.ConfigurationImpl;
-import com.tencent.polaris.plugins.router.healthy.RecoverRouterConfig;
+import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI;
+import com.tencent.polaris.circuitbreak.factory.CircuitBreakAPIFactory;
+import com.tencent.polaris.client.api.SDKContext;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory;
+import org.springframework.cloud.client.circuitbreaker.Customizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+
/**
- * Autoconfiguration at bootstrap phase.
+ * Autoconfiguration for PolarisCircuitBreaker.
*
* @author lepdou 2022-03-29
*/
@@ -39,40 +48,28 @@ import org.springframework.context.annotation.Configuration;
@AutoConfigureAfter(RpcEnhancementAutoConfiguration.class)
public class PolarisCircuitBreakerAutoConfiguration {
+ @Autowired(required = false)
+ private List> customizers = new ArrayList<>();
+
@Bean
- public CircuitBreakerConfigModifier circuitBreakerConfigModifier(RpcEnhancementReporterProperties properties) {
- return new CircuitBreakerConfigModifier(properties);
+ @ConditionalOnMissingBean(CircuitBreakAPI.class)
+ public CircuitBreakAPI circuitBreakAPI(SDKContext polarisContext) {
+ return CircuitBreakAPIFactory.createCircuitBreakAPIByContext(polarisContext);
}
- public static class CircuitBreakerConfigModifier implements PolarisConfigModifier {
-
- private final RpcEnhancementReporterProperties properties;
-
- public CircuitBreakerConfigModifier(RpcEnhancementReporterProperties properties) {
- this.properties = properties;
- }
-
- @Override
- public void modify(ConfigurationImpl configuration) {
- properties.setEnabled(true);
-
- // Turn on circuitbreaker configuration
- configuration.getConsumer().getCircuitBreaker().setEnable(true);
-
- // Set excludeCircuitBreakInstances to true
- RecoverRouterConfig recoverRouterConfig = configuration.getConsumer().getServiceRouter()
- .getPluginConfig(ServiceRouterConfig.DEFAULT_ROUTER_RECOVER, RecoverRouterConfig.class);
-
- recoverRouterConfig.setExcludeCircuitBreakInstances(true);
-
- // Update modified config to source properties
- configuration.getConsumer().getServiceRouter()
- .setPluginConfig(ServiceRouterConfig.DEFAULT_ROUTER_RECOVER, recoverRouterConfig);
- }
+ @Bean
+ @ConditionalOnMissingBean(CircuitBreakerFactory.class)
+ public CircuitBreakerFactory polarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI) {
+ PolarisCircuitBreakerFactory factory = new PolarisCircuitBreakerFactory(circuitBreakAPI);
+ customizers.forEach(customizer -> customizer.customize(factory));
+ return factory;
+ }
- @Override
- public int getOrder() {
- return ContextConstant.ModifierOrder.CIRCUIT_BREAKER_ORDER;
- }
+ @Bean
+ @ConditionalOnBean(RpcEnhancementReporterProperties.class)
+ @ConditionalOnMissingBean(CircuitBreakerConfigModifier.class)
+ public CircuitBreakerConfigModifier circuitBreakerConfigModifier(RpcEnhancementReporterProperties properties) {
+ return new CircuitBreakerConfigModifier(properties);
}
+
}
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerBootstrapConfiguration.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerBootstrapConfiguration.java
index 9d21fbf0d..c1cafea0b 100644
--- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerBootstrapConfiguration.java
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerBootstrapConfiguration.java
@@ -28,7 +28,7 @@ import org.springframework.context.annotation.Import;
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty("spring.cloud.polaris.enabled")
-@Import(PolarisCircuitBreakerAutoConfiguration.class)
+@Import({PolarisCircuitBreakerAutoConfiguration.class, ReactivePolarisCircuitBreakerAutoConfiguration.class, PolarisCircuitBreakerFeignClientAutoConfiguration.class})
public class PolarisCircuitBreakerBootstrapConfiguration {
}
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerFeignClientAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerFeignClientAutoConfiguration.java
new file mode 100644
index 000000000..91096e1e6
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerFeignClientAutoConfiguration.java
@@ -0,0 +1,46 @@
+/*
+ * 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 com.tencent.cloud.polaris.circuitbreaker.feign.PolarisCircuitBreakerNameResolver;
+import feign.Feign;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.cloud.openfeign.CircuitBreakerNameResolver;
+import org.springframework.cloud.openfeign.FeignClientFactoryBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * PolarisCircuitBreakerFeignClientAutoConfiguration.
+ *
+ * @author seansyyu 2023-02-28
+ */
+@Configuration(proxyBeanMethods = false)
+@ConditionalOnClass({ Feign.class, FeignClientFactoryBean.class })
+@ConditionalOnPolarisCircuitBreakerEnabled
+public class PolarisCircuitBreakerFeignClientAutoConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean(CircuitBreakerNameResolver.class)
+ public CircuitBreakerNameResolver polarisCircuitBreakerNameResolver() {
+ return new PolarisCircuitBreakerNameResolver();
+ }
+
+}
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/ReactivePolarisCircuitBreakerAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/ReactivePolarisCircuitBreakerAutoConfiguration.java
new file mode 100644
index 000000000..58ca348a5
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/ReactivePolarisCircuitBreakerAutoConfiguration.java
@@ -0,0 +1,76 @@
+/*
+ * 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.List;
+
+import com.tencent.cloud.polaris.circuitbreaker.ReactivePolarisCircuitBreakerFactory;
+import com.tencent.cloud.polaris.circuitbreaker.common.CircuitBreakerConfigModifier;
+import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementAutoConfiguration;
+import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
+import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI;
+import com.tencent.polaris.circuitbreak.factory.CircuitBreakAPIFactory;
+import com.tencent.polaris.client.api.SDKContext;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.cloud.client.circuitbreaker.Customizer;
+import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreakerFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * AutoConfiguration for ReactivePolarisCircuitBreaker.
+ *
+ * @author seanyu 2023-02-27
+ */
+@Configuration(proxyBeanMethods = false)
+@ConditionalOnClass(name = { "reactor.core.publisher.Mono", "reactor.core.publisher.Flux" })
+@ConditionalOnPolarisCircuitBreakerEnabled
+@AutoConfigureAfter(RpcEnhancementAutoConfiguration.class)
+public class ReactivePolarisCircuitBreakerAutoConfiguration {
+
+ @Autowired(required = false)
+ private List> customizers = new ArrayList<>();
+
+ @Bean
+ @ConditionalOnMissingBean(CircuitBreakAPI.class)
+ public CircuitBreakAPI circuitBreakAPI(SDKContext polarisContext) {
+ return CircuitBreakAPIFactory.createCircuitBreakAPIByContext(polarisContext);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean(ReactiveCircuitBreakerFactory.class)
+ public ReactiveCircuitBreakerFactory reactiveCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI) {
+ ReactivePolarisCircuitBreakerFactory factory = new ReactivePolarisCircuitBreakerFactory(circuitBreakAPI);
+ customizers.forEach(customizer -> customizer.customize(factory));
+ return factory;
+ }
+
+ @Bean
+ @ConditionalOnBean(RpcEnhancementReporterProperties.class)
+ @ConditionalOnMissingBean(CircuitBreakerConfigModifier.class)
+ public CircuitBreakerConfigModifier reactiveCircuitBreakerConfigModifier(RpcEnhancementReporterProperties properties) {
+ return new CircuitBreakerConfigModifier(properties);
+ }
+
+}
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerNameResolver.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerNameResolver.java
new file mode 100644
index 000000000..2b1689c45
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerNameResolver.java
@@ -0,0 +1,51 @@
+/*
+ * 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.feign;
+
+import java.lang.reflect.Method;
+
+import com.tencent.cloud.common.metadata.MetadataContext;
+import feign.Target;
+
+import org.springframework.cloud.openfeign.CircuitBreakerNameResolver;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import static org.springframework.core.annotation.AnnotatedElementUtils.findMergedAnnotation;
+
+/**
+ * PolarisCircuitBreakerNameResolver.
+ *
+ * @author seanyu 2023-02-27
+ */
+public class PolarisCircuitBreakerNameResolver implements CircuitBreakerNameResolver {
+
+ @Override
+ public String resolveCircuitBreakerName(String feignClientName, Target> target, Method method) {
+ RequestMapping requestMapping = findMergedAnnotation(method, RequestMapping.class);
+ String path = "";
+ if (requestMapping != null) {
+ path = requestMapping.path().length == 0 ?
+ requestMapping.value().length == 0 ? "" : requestMapping.value()[0] :
+ requestMapping.path()[0];
+ }
+ return "".equals(path) ?
+ MetadataContext.LOCAL_NAMESPACE + "#" + feignClientName :
+ MetadataContext.LOCAL_NAMESPACE + "#" + feignClientName + "#" + path;
+ }
+
+}
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/gateway/PolarisCircuitBreakerFilterFactory.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/gateway/PolarisCircuitBreakerFilterFactory.java
new file mode 100644
index 000000000..90a9749fe
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/gateway/PolarisCircuitBreakerFilterFactory.java
@@ -0,0 +1,228 @@
+/*
+ * 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.gateway;
+
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import com.tencent.polaris.circuitbreak.client.exception.CallAbortedException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import reactor.core.publisher.Mono;
+
+import org.springframework.beans.InvalidPropertyException;
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreaker;
+import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreakerFactory;
+import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient;
+import org.springframework.cloud.gateway.discovery.DiscoveryLocatorProperties;
+import org.springframework.cloud.gateway.filter.GatewayFilter;
+import org.springframework.cloud.gateway.filter.GatewayFilterChain;
+import org.springframework.cloud.gateway.filter.factory.SpringCloudCircuitBreakerFilterFactory;
+import org.springframework.cloud.gateway.support.HttpStatusHolder;
+import org.springframework.cloud.gateway.support.ServiceUnavailableException;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.util.StringUtils;
+import org.springframework.web.reactive.DispatcherHandler;
+import org.springframework.web.server.ResponseStatusException;
+import org.springframework.web.server.ServerWebExchange;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import static java.util.Optional.ofNullable;
+import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator;
+import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.CIRCUITBREAKER_EXECUTION_EXCEPTION_ATTR;
+import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR;
+import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.containsEncodedParts;
+import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.reset;
+
+/**
+ * PolarisCircuitBreakerFilterFactory.
+ * mostly copy from SpringCloudCircuitBreakerFilterFactory, but create ReactiveCircuitBreaker per request to build method level CircuitBreaker.
+ *
+ * @author seanyu 2023-02-27
+ */
+public class PolarisCircuitBreakerFilterFactory extends SpringCloudCircuitBreakerFilterFactory {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(PolarisCircuitBreakerFilterFactory.class);
+
+ private String routeIdPrefix;
+
+ private final ReactiveCircuitBreakerFactory reactiveCircuitBreakerFactory;
+
+ private final ObjectProvider dispatcherHandlerProvider;
+
+ // do not use this dispatcherHandler directly, use getDispatcherHandler() instead.
+ private volatile DispatcherHandler dispatcherHandler;
+
+ public PolarisCircuitBreakerFilterFactory(
+ ReactiveCircuitBreakerFactory reactiveCircuitBreakerFactory,
+ ObjectProvider dispatcherHandlerProvider,
+ ReactiveDiscoveryClient discoveryClient,
+ DiscoveryLocatorProperties properties
+ ) {
+ super(reactiveCircuitBreakerFactory, dispatcherHandlerProvider);
+ this.reactiveCircuitBreakerFactory = reactiveCircuitBreakerFactory;
+ this.dispatcherHandlerProvider = dispatcherHandlerProvider;
+ if (discoveryClient != null && properties != null) {
+ if (StringUtils.hasText(properties.getRouteIdPrefix())) {
+ routeIdPrefix = properties.getRouteIdPrefix();
+ }
+ else {
+ routeIdPrefix = discoveryClient.getClass().getSimpleName() + "_";
+ }
+ }
+ }
+
+ private void addExceptionDetails(Throwable t, ServerWebExchange exchange) {
+ ofNullable(t).ifPresent(
+ exception -> exchange.getAttributes().put(CIRCUITBREAKER_EXECUTION_EXCEPTION_ATTR, exception));
+ }
+
+ private DispatcherHandler getDispatcherHandler() {
+ if (dispatcherHandler == null) {
+ dispatcherHandler = dispatcherHandlerProvider.getIfAvailable();
+ }
+ return dispatcherHandler;
+ }
+
+ private String getCircuitBreakerId(Config config) {
+ if (!StringUtils.hasText(config.getName()) && StringUtils.hasText(config.getRouteId())) {
+ if (routeIdPrefix != null && config.getRouteId().startsWith(routeIdPrefix)) {
+ return config.getRouteId().replace(routeIdPrefix, "");
+ }
+ return config.getRouteId();
+ }
+ return config.getName();
+ }
+
+ private boolean isNumeric(String statusString) {
+ try {
+ Integer.parseInt(statusString);
+ return true;
+ }
+ catch (NumberFormatException e) {
+ return false;
+ }
+ }
+
+ private List getSeriesStatus(String series) {
+ if (!Arrays.asList("1**", "2**", "3**", "4**", "5**").contains(series)) {
+ throw new InvalidPropertyException(Config.class, "statusCodes", "polaris circuit breaker status code can only be a numeric http status, or a http series pattern, e.g. [\"1**\",\"2**\",\"3**\",\"4**\",\"5**\"]");
+ }
+ HttpStatus[] allHttpStatus = HttpStatus.values();
+ if (series.startsWith("1")) {
+ return Arrays.stream(allHttpStatus).filter(HttpStatus::is1xxInformational).collect(Collectors.toList());
+ }
+ else if (series.startsWith("2")) {
+ return Arrays.stream(allHttpStatus).filter(HttpStatus::is2xxSuccessful).collect(Collectors.toList());
+ }
+ else if (series.startsWith("3")) {
+ return Arrays.stream(allHttpStatus).filter(HttpStatus::is3xxRedirection).collect(Collectors.toList());
+ }
+ else if (series.startsWith("4")) {
+ return Arrays.stream(allHttpStatus).filter(HttpStatus::is4xxClientError).collect(Collectors.toList());
+ }
+ else if (series.startsWith("5")) {
+ return Arrays.stream(allHttpStatus).filter(HttpStatus::is5xxServerError).collect(Collectors.toList());
+ }
+ return Arrays.asList(allHttpStatus);
+ }
+
+ @Override
+ public GatewayFilter apply(Config config) {
+ Set statuses = config.getStatusCodes().stream()
+ .flatMap(statusCode -> {
+ List httpStatuses = new ArrayList<>();
+ if (isNumeric(statusCode)) {
+ httpStatuses.add(HttpStatusHolder.parse(statusCode).getHttpStatus());
+ }
+ else {
+ httpStatuses.addAll(getSeriesStatus(statusCode));
+ }
+ return httpStatuses.stream();
+ })
+ .filter(Objects::nonNull)
+ .collect(Collectors.toSet());
+ String circuitBreakerId = getCircuitBreakerId(config);
+ return new GatewayFilter() {
+ @Override
+ public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
+ String path = exchange.getRequest().getPath().value();
+ ReactiveCircuitBreaker cb = reactiveCircuitBreakerFactory.create(circuitBreakerId + "#" + path);
+ return cb.run(chain.filter(exchange).doOnSuccess(v -> {
+ if (statuses.contains(exchange.getResponse().getStatusCode())) {
+ HttpStatus status = exchange.getResponse().getStatusCode();
+ throw new CircuitBreakerStatusCodeException(status);
+ }
+ }), t -> {
+ if (config.getFallbackUri() == null) {
+ return Mono.error(t);
+ }
+
+ exchange.getResponse().setStatusCode(null);
+ reset(exchange);
+
+ // TODO: copied from RouteToRequestUrlFilter
+ URI uri = exchange.getRequest().getURI();
+ // TODO: assume always?
+ boolean encoded = containsEncodedParts(uri);
+ URI requestUrl = UriComponentsBuilder.fromUri(uri).host(null).port(null)
+ .uri(config.getFallbackUri()).scheme(null).build(encoded).toUri();
+ exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);
+ addExceptionDetails(t, exchange);
+
+ // Reset the exchange
+ reset(exchange);
+
+ ServerHttpRequest request = exchange.getRequest().mutate().uri(requestUrl).build();
+ return getDispatcherHandler().handle(exchange.mutate().request(request).build());
+ }).onErrorResume(t -> handleErrorWithoutFallback(t, config.isResumeWithoutError()));
+ }
+
+ @Override
+ public String toString() {
+ return filterToStringCreator(PolarisCircuitBreakerFilterFactory.this)
+ .append("name", config.getName()).append("fallback", config.getFallbackUri()).toString();
+ }
+ };
+
+ }
+
+ @Override
+ protected Mono handleErrorWithoutFallback(Throwable t, boolean resumeWithoutError) {
+ if (t instanceof java.util.concurrent.TimeoutException) {
+ return Mono.error(new ResponseStatusException(HttpStatus.GATEWAY_TIMEOUT, t.getMessage(), t));
+ }
+ if (t instanceof CallAbortedException) {
+ LOGGER.debug("PolarisCircuitBreaker CallAbortedException: {}", t.getMessage());
+ return Mono.error(new ServiceUnavailableException());
+ }
+ if (resumeWithoutError) {
+ return Mono.empty();
+ }
+ return Mono.error(t);
+ }
+
+}
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/reactor/PolarisCircuitBreakerFluxOperator.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/reactor/PolarisCircuitBreakerFluxOperator.java
new file mode 100644
index 000000000..faad71135
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/reactor/PolarisCircuitBreakerFluxOperator.java
@@ -0,0 +1,57 @@
+/*
+ * 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.reactor;
+
+import com.tencent.polaris.circuitbreak.api.InvokeHandler;
+import com.tencent.polaris.circuitbreak.client.exception.CallAbortedException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import reactor.core.CoreSubscriber;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.FluxOperator;
+import reactor.core.publisher.Operators;
+
+/**
+ * FluxOperator for PolarisCircuitBreaker.
+ *
+ * @author seanyu 2023-02-27
+ */
+public class PolarisCircuitBreakerFluxOperator extends FluxOperator {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(PolarisCircuitBreakerFluxOperator.class);
+
+ private final InvokeHandler invokeHandler;
+
+ protected PolarisCircuitBreakerFluxOperator(Flux extends T> source, InvokeHandler invokeHandler) {
+ super(source);
+ this.invokeHandler = invokeHandler;
+ }
+
+ @Override
+ public void subscribe(CoreSubscriber super T> actual) {
+ try {
+ invokeHandler.acquirePermission();
+ source.subscribe(new PolarisCircuitBreakerReactorSubscriber<>(invokeHandler, actual, false));
+ }
+ catch (CallAbortedException e) {
+ LOGGER.debug("ReactivePolarisCircuitBreaker CallAbortedException: {}", e.getMessage());
+ Operators.error(actual, e);
+ }
+ }
+
+}
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/reactor/PolarisCircuitBreakerMonoOperator.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/reactor/PolarisCircuitBreakerMonoOperator.java
new file mode 100644
index 000000000..6f0a44fef
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/reactor/PolarisCircuitBreakerMonoOperator.java
@@ -0,0 +1,57 @@
+/*
+ * 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.reactor;
+
+import com.tencent.polaris.circuitbreak.api.InvokeHandler;
+import com.tencent.polaris.circuitbreak.client.exception.CallAbortedException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import reactor.core.CoreSubscriber;
+import reactor.core.publisher.Mono;
+import reactor.core.publisher.MonoOperator;
+import reactor.core.publisher.Operators;
+
+/**
+ * MonoOperator for PolarisCircuitBreaker.
+ *
+ * @author seanyu 2023-02-27
+ */
+public class PolarisCircuitBreakerMonoOperator extends MonoOperator {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(PolarisCircuitBreakerMonoOperator.class);
+
+ private final InvokeHandler invokeHandler;
+
+ protected PolarisCircuitBreakerMonoOperator(Mono extends T> source, InvokeHandler invokeHandler) {
+ super(source);
+ this.invokeHandler = invokeHandler;
+ }
+
+ @Override
+ public void subscribe(CoreSubscriber super T> actual) {
+ try {
+ invokeHandler.acquirePermission();
+ source.subscribe(new PolarisCircuitBreakerReactorSubscriber<>(invokeHandler, actual, true));
+ }
+ catch (CallAbortedException e) {
+ LOGGER.debug("ReactivePolarisCircuitBreaker CallAbortedException: {}", e.getMessage());
+ Operators.error(actual, e);
+ }
+ }
+
+}
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/reactor/PolarisCircuitBreakerReactorSubscriber.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/reactor/PolarisCircuitBreakerReactorSubscriber.java
new file mode 100644
index 000000000..202f63369
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/reactor/PolarisCircuitBreakerReactorSubscriber.java
@@ -0,0 +1,119 @@
+/*
+ * 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.reactor;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import com.tencent.polaris.circuitbreak.api.InvokeHandler;
+import com.tencent.polaris.circuitbreak.api.pojo.InvokeContext;
+import org.reactivestreams.Subscription;
+import reactor.core.CoreSubscriber;
+import reactor.core.publisher.BaseSubscriber;
+import reactor.util.context.Context;
+
+/**
+ * Reactor Subscriber for PolarisCircuitBreaker.
+ *
+ * @author seanyu 2023-02-27
+ */
+public class PolarisCircuitBreakerReactorSubscriber extends BaseSubscriber {
+
+ private final InvokeHandler invokeHandler;
+
+
+ private final CoreSubscriber super T> downstreamSubscriber;
+
+ private final long startTimeMilli;
+ private final boolean singleProducer;
+
+ private final AtomicBoolean successSignaled = new AtomicBoolean(false);
+ private final AtomicBoolean eventWasEmitted = new AtomicBoolean(false);
+
+ public PolarisCircuitBreakerReactorSubscriber(InvokeHandler invokeHandler, CoreSubscriber super T> downstreamSubscriber, boolean singleProducer) {
+ this.invokeHandler = invokeHandler;
+ this.downstreamSubscriber = downstreamSubscriber;
+ this.singleProducer = singleProducer;
+ this.startTimeMilli = System.currentTimeMillis();
+ }
+
+ @Override
+ public Context currentContext() {
+ return downstreamSubscriber.currentContext();
+ }
+
+ @Override
+ protected void hookOnSubscribe(Subscription subscription) {
+ downstreamSubscriber.onSubscribe(this);
+ }
+
+ @Override
+ protected void hookOnNext(T value) {
+ if (!isDisposed()) {
+ if (singleProducer && successSignaled.compareAndSet(false, true)) {
+ long delay = System.currentTimeMillis() - startTimeMilli;
+ InvokeContext.ResponseContext responseContext = new InvokeContext.ResponseContext();
+ responseContext.setDuration(delay);
+ responseContext.setDurationUnit(TimeUnit.MILLISECONDS);
+ responseContext.setResult(value);
+ invokeHandler.onSuccess(responseContext);
+ }
+ eventWasEmitted.set(true);
+
+ downstreamSubscriber.onNext(value);
+ }
+ }
+
+ @Override
+ protected void hookOnComplete() {
+ if (successSignaled.compareAndSet(false, true)) {
+ long delay = System.currentTimeMillis() - startTimeMilli;
+ InvokeContext.ResponseContext responseContext = new InvokeContext.ResponseContext();
+ responseContext.setDuration(delay);
+ responseContext.setDurationUnit(TimeUnit.MILLISECONDS);
+ invokeHandler.onSuccess(responseContext);
+ }
+
+ downstreamSubscriber.onComplete();
+ }
+
+ @Override
+ public void hookOnCancel() {
+ if (!successSignaled.get()) {
+ if (eventWasEmitted.get()) {
+ long delay = System.currentTimeMillis() - startTimeMilli;
+ InvokeContext.ResponseContext responseContext = new InvokeContext.ResponseContext();
+ responseContext.setDuration(delay);
+ responseContext.setDurationUnit(TimeUnit.MILLISECONDS);
+ invokeHandler.onSuccess(responseContext);
+ }
+ }
+ }
+
+ @Override
+ protected void hookOnError(Throwable e) {
+ long delay = System.currentTimeMillis() - startTimeMilli;
+ InvokeContext.ResponseContext responseContext = new InvokeContext.ResponseContext();
+ responseContext.setDuration(delay);
+ responseContext.setDurationUnit(TimeUnit.MILLISECONDS);
+ responseContext.setError(e);
+ invokeHandler.onError(responseContext);
+ downstreamSubscriber.onError(e);
+ }
+
+}
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/reactor/PolarisCircuitBreakerReactorTransformer.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/reactor/PolarisCircuitBreakerReactorTransformer.java
new file mode 100644
index 000000000..b7fa450e1
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/reactor/PolarisCircuitBreakerReactorTransformer.java
@@ -0,0 +1,53 @@
+/*
+ * 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.reactor;
+
+import java.util.function.Function;
+
+import com.tencent.polaris.circuitbreak.api.InvokeHandler;
+import org.reactivestreams.Publisher;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+/**
+ * Reactor Transformer for PolarisCircuitBreaker.
+ *
+ * @author seanyu 2023-02-27
+ */
+public class PolarisCircuitBreakerReactorTransformer implements Function, Publisher> {
+
+ private final InvokeHandler invokeHandler;
+
+ public PolarisCircuitBreakerReactorTransformer(InvokeHandler invokeHandler) {
+ this.invokeHandler = invokeHandler;
+ }
+
+ @Override
+ public Publisher apply(Publisher publisher) {
+ if (publisher instanceof Mono) {
+ return new PolarisCircuitBreakerMonoOperator<>((Mono extends T>) publisher, invokeHandler);
+ }
+ else if (publisher instanceof Flux) {
+ return new PolarisCircuitBreakerFluxOperator<>((Flux extends T>) publisher, invokeHandler);
+ }
+ else {
+ throw new IllegalStateException("Publisher type is not supported: " + publisher.getClass().getCanonicalName());
+ }
+ }
+
+}
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/util/PolarisCircuitBreakerUtils.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/util/PolarisCircuitBreakerUtils.java
new file mode 100644
index 000000000..885e2917b
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/util/PolarisCircuitBreakerUtils.java
@@ -0,0 +1,54 @@
+/*
+ * 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.util;
+
+import com.tencent.cloud.common.metadata.MetadataContext;
+
+import org.springframework.util.Assert;
+
+/**
+ * PolarisCircuitBreakerUtils.
+ *
+ * @author seanyu 2023-02-27
+ */
+public final class PolarisCircuitBreakerUtils {
+
+ private PolarisCircuitBreakerUtils() {
+
+ }
+
+ /**
+ *
+ * @param id CircuitBreakerId
+ * Format: namespace#service#method or service#method or service ,
+ * namespace set as default spring.cloud.polaris.namespace if absent
+ * @return String[]{namespace, service, method}
+ */
+ public static String[] resolveCircuitBreakerId(String id) {
+ Assert.hasText(id, "A CircuitBreaker must have an id. Id could be : namespace#service#method or service#method or service");
+ String[] polarisCircuitBreakerMetaData = id.split("#");
+ if (polarisCircuitBreakerMetaData.length == 2) {
+ return new String[]{MetadataContext.LOCAL_NAMESPACE, polarisCircuitBreakerMetaData[0], polarisCircuitBreakerMetaData[1]};
+ }
+ if (polarisCircuitBreakerMetaData.length == 3) {
+ return new String[]{polarisCircuitBreakerMetaData[0], polarisCircuitBreakerMetaData[1], polarisCircuitBreakerMetaData[2]};
+ }
+ return new String[]{MetadataContext.LOCAL_NAMESPACE, id, ""};
+ }
+
+}
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/resources/META-INF/spring.factories b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/resources/META-INF/spring.factories
index 418da24ab..a873ed563 100644
--- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/resources/META-INF/spring.factories
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/resources/META-INF/spring.factories
@@ -1,4 +1,7 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
- com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerAutoConfiguration
+ com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerAutoConfiguration,\
+ com.tencent.cloud.polaris.circuitbreaker.config.ReactivePolarisCircuitBreakerAutoConfiguration,\
+ com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerFeignClientAutoConfiguration,\
+ com.tencent.cloud.polaris.circuitbreaker.config.GatewayPolarisCircuitBreakerAutoConfiguration
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerBootstrapConfiguration
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerAutoConfigurationTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerAutoConfigurationTest.java
new file mode 100644
index 000000000..24801dbea
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerAutoConfigurationTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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.common.CircuitBreakerConfigModifier;
+import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerAutoConfiguration;
+import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerFeignClientAutoConfiguration;
+import com.tencent.cloud.polaris.circuitbreaker.config.ReactivePolarisCircuitBreakerAutoConfiguration;
+import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration;
+import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementAutoConfiguration;
+import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI;
+import org.junit.jupiter.api.Test;
+
+import org.springframework.boot.autoconfigure.AutoConfigurations;
+import org.springframework.boot.test.context.runner.ApplicationContextRunner;
+import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory;
+import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreakerFactory;
+import org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration;
+import org.springframework.cloud.openfeign.CircuitBreakerNameResolver;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Test for {@link PolarisCircuitBreakerAutoConfiguration}.
+ *
+ * @author Haotian Zhang
+ */
+public class PolarisCircuitBreakerAutoConfigurationTest {
+ private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
+ .withConfiguration(AutoConfigurations.of(
+ PolarisContextAutoConfiguration.class,
+ RpcEnhancementAutoConfiguration.class,
+ LoadBalancerAutoConfiguration.class,
+ PolarisCircuitBreakerFeignClientAutoConfiguration.class,
+ PolarisCircuitBreakerAutoConfiguration.class))
+ .withPropertyValues("spring.cloud.polaris.circuitbreaker.enabled=true");
+
+ private final ApplicationContextRunner reactiveContextRunner = new ApplicationContextRunner()
+ .withConfiguration(AutoConfigurations.of(
+ PolarisContextAutoConfiguration.class,
+ RpcEnhancementAutoConfiguration.class,
+ LoadBalancerAutoConfiguration.class,
+ ReactivePolarisCircuitBreakerAutoConfiguration.class))
+ .withPropertyValues("spring.cloud.polaris.circuitbreaker.enabled=true");
+
+ @Test
+ public void testDefaultInitialization() {
+ this.contextRunner.run(context -> {
+ assertThat(context).hasSingleBean(PolarisCircuitBreakerAutoConfiguration.class);
+ assertThat(context).hasSingleBean(CircuitBreakerFactory.class);
+ assertThat(context).hasSingleBean(CircuitBreakerConfigModifier.class);
+ assertThat(context).hasSingleBean(CircuitBreakAPI.class);
+ assertThat(context).hasSingleBean(CircuitBreakerNameResolver.class);
+ });
+ }
+
+ @Test
+ public void testReactiveInitialization() {
+ this.reactiveContextRunner.run(context -> {
+ assertThat(context).hasSingleBean(ReactivePolarisCircuitBreakerAutoConfiguration.class);
+ assertThat(context).hasSingleBean(ReactiveCircuitBreakerFactory.class);
+ assertThat(context).hasSingleBean(CircuitBreakerConfigModifier.class);
+ assertThat(context).hasSingleBean(CircuitBreakAPI.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/PolarisCircuitBreakerBootstrapConfigurationTest.java
similarity index 69%
rename from spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerBootstrapConfigurationTest.java
rename to spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerBootstrapConfigurationTest.java
index 9213272cd..c78784308 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/PolarisCircuitBreakerBootstrapConfigurationTest.java
@@ -15,8 +15,12 @@
* specific language governing permissions and limitations under the License.
*/
-package com.tencent.cloud.polaris.circuitbreaker.config;
+package com.tencent.cloud.polaris.circuitbreaker;
+import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerAutoConfiguration;
+import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerBootstrapConfiguration;
+import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerFeignClientAutoConfiguration;
+import com.tencent.cloud.polaris.circuitbreaker.config.ReactivePolarisCircuitBreakerAutoConfiguration;
import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementAutoConfiguration;
import org.junit.jupiter.api.Test;
@@ -34,10 +38,10 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
public class PolarisCircuitBreakerBootstrapConfigurationTest {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
- .withConfiguration(AutoConfigurations.of(PolarisContextAutoConfiguration.class,
+ .withConfiguration(AutoConfigurations.of(
+ PolarisContextAutoConfiguration.class,
RpcEnhancementAutoConfiguration.class,
LoadBalancerAutoConfiguration.class,
- RpcEnhancementAutoConfiguration.class,
PolarisCircuitBreakerBootstrapConfiguration.class))
.withPropertyValues("spring.cloud.polaris.enabled=true")
.withPropertyValues("spring.cloud.polaris.circuitbreaker.enabled=true");
@@ -45,8 +49,9 @@ public class PolarisCircuitBreakerBootstrapConfigurationTest {
@Test
public void testDefaultInitialization() {
this.contextRunner.run(context -> {
- assertThat(context).hasSingleBean(
- PolarisCircuitBreakerAutoConfiguration.CircuitBreakerConfigModifier.class);
+ assertThat(context).hasSingleBean(PolarisCircuitBreakerAutoConfiguration.class);
+ assertThat(context).hasSingleBean(PolarisCircuitBreakerFeignClientAutoConfiguration.class);
+ assertThat(context).hasSingleBean(ReactivePolarisCircuitBreakerAutoConfiguration.class);
});
}
}
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerFeignIntegrationTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerFeignIntegrationTest.java
new file mode 100644
index 000000000..f2963b9b3
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerFeignIntegrationTest.java
@@ -0,0 +1,178 @@
+/*
+ * 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.PolarisCircuitBreakerFeignClientAutoConfiguration;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+import org.springframework.cloud.openfeign.FallbackFactory;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
+
+/**
+ * @author sean yu
+ */
+@ExtendWith(SpringExtension.class)
+@SpringBootTest(webEnvironment = RANDOM_PORT,
+ classes = PolarisCircuitBreakerFeignIntegrationTest.TestConfig.class,
+ properties = {
+ "spring.cloud.gateway.enabled=false",
+ "feign.circuitbreaker.enabled=true",
+ "spring.cloud.polaris.namespace=default",
+ "spring.cloud.polaris.service=Test"
+})
+@DirtiesContext
+public class PolarisCircuitBreakerFeignIntegrationTest {
+
+ @Autowired
+ private EchoService echoService;
+
+ @Autowired
+ private FooService fooService;
+
+ @Autowired
+ private BarService barService;
+
+ @Autowired
+ private BazService bazService;
+
+ @Test
+ public void contextLoads() throws Exception {
+ assertThat(echoService).isNotNull();
+ assertThat(fooService).isNotNull();
+ }
+
+ @Test
+ public void testFeignClient() {
+ assertThat(echoService.echo("test")).isEqualTo("echo fallback");
+ assertThat(fooService.echo("test")).isEqualTo("foo fallback");
+
+ assertThatThrownBy(() -> {
+ barService.bar();
+ }).isInstanceOf(Exception.class);
+
+ assertThatThrownBy(() -> {
+ bazService.baz();
+ }).isInstanceOf(Exception.class);
+
+ assertThat(fooService.toString()).isNotEqualTo(echoService.toString());
+ assertThat(fooService.hashCode()).isNotEqualTo(echoService.hashCode());
+ assertThat(echoService.equals(fooService)).isEqualTo(Boolean.FALSE);
+ }
+
+ @Configuration
+ @EnableAutoConfiguration
+ @ImportAutoConfiguration({ PolarisCircuitBreakerFeignClientAutoConfiguration.class })
+ @EnableFeignClients
+ public static class TestConfig {
+
+ @Bean
+ public EchoServiceFallback echoServiceFallback() {
+ return new EchoServiceFallback();
+ }
+
+ @Bean
+ public CustomFallbackFactory customFallbackFactory() {
+ return new CustomFallbackFactory();
+ }
+
+ }
+
+ @FeignClient(value = "test-service", fallback = EchoServiceFallback.class)
+ public interface EchoService {
+
+ @RequestMapping(path = "echo/{str}")
+ String echo(@RequestParam("str") String param);
+
+ }
+
+ @FeignClient(value = "foo-service", fallbackFactory = CustomFallbackFactory.class)
+ public interface FooService {
+
+ @RequestMapping("echo/{str}")
+ String echo(@RequestParam("str") String param);
+
+ }
+
+ @FeignClient("bar-service")
+ public interface BarService {
+
+ @RequestMapping(path = "bar")
+ String bar();
+
+ }
+
+ public interface BazService {
+
+ @RequestMapping(path = "baz")
+ String baz();
+
+ }
+
+ @FeignClient("baz-service")
+ public interface BazClient extends BazService {
+
+ }
+
+ public static class EchoServiceFallback implements EchoService {
+
+ @Override
+ public String echo(@RequestParam("str") String param) {
+ return "echo fallback";
+ }
+
+ }
+
+ public static class FooServiceFallback implements FooService {
+
+ @Override
+ public String echo(@RequestParam("str") String param) {
+ return "foo fallback";
+ }
+
+ }
+
+ public static class CustomFallbackFactory
+ implements FallbackFactory {
+
+ private FooService fooService = new FooServiceFallback();
+
+ @Override
+ public FooService create(Throwable throwable) {
+ return fooService;
+ }
+
+ }
+
+}
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerGatewayIntegrationTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerGatewayIntegrationTest.java
new file mode 100644
index 000000000..cf0823417
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerGatewayIntegrationTest.java
@@ -0,0 +1,148 @@
+/*
+ * 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.HashSet;
+import java.util.Set;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import reactor.core.publisher.Mono;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock;
+import org.springframework.cloud.gateway.route.RouteLocator;
+import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.test.web.reactive.server.WebTestClient;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
+import static com.github.tomakehurst.wiremock.client.WireMock.get;
+import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
+import static org.assertj.core.api.Assertions.assertThat;
+
+
+/**
+ * @author sean yu
+ */
+@ExtendWith(SpringExtension.class)
+@SpringBootTest(
+ webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
+ properties = {
+ "spring.cloud.gateway.enabled=true",
+ "spring.cloud.polaris.namespace=default",
+ "spring.cloud.polaris.service=Test",
+ "spring.main.web-application-type=reactive",
+ "httpbin=http://localhost:${wiremock.server.port}"
+ },
+ classes = PolarisCircuitBreakerGatewayIntegrationTest.TestApplication.class
+)
+@AutoConfigureWireMock(port = 0)
+@ActiveProfiles("test-gateway")
+@AutoConfigureWebTestClient(timeout = "10000")
+public class PolarisCircuitBreakerGatewayIntegrationTest {
+
+ @Autowired
+ private WebTestClient webClient;
+
+ @Test
+ public void fallback() throws Exception {
+
+ stubFor(get(urlEqualTo("/err"))
+ .willReturn(aResponse()
+ .withStatus(500)
+ .withBody("err")
+ .withFixedDelay(3000)));
+
+ webClient
+ .get().uri("/err")
+ .header("Host", "www.circuitbreaker.com")
+ .exchange()
+ .expectStatus().isOk()
+ .expectBody()
+ .consumeWith(
+ response -> assertThat(response.getResponseBody()).isEqualTo("fallback".getBytes()));
+ }
+
+ @Test
+ public void noFallback() throws Exception {
+
+ stubFor(get(urlEqualTo("/err-no-fallback"))
+ .willReturn(aResponse()
+ .withStatus(500)
+ .withBody("err")
+ .withFixedDelay(3000)));
+
+ webClient
+ .get().uri("/err-no-fallback")
+ .header("Host", "www.circuitbreaker-no-fallback.com")
+ .exchange()
+ .expectStatus().isEqualTo(500);
+ }
+
+
+ @Configuration
+ @EnableAutoConfiguration
+ public static class TestApplication {
+
+ @Bean
+ public RouteLocator myRoutes(RouteLocatorBuilder builder) {
+ String httpUri = "http://httpbin.org:80";
+ Set codeSets = new HashSet<>();
+ codeSets.add("4**");
+ codeSets.add("5**");
+ return builder.routes()
+ .route(p -> p
+ .host("*.circuitbreaker.com")
+ .filters(f -> f
+ .circuitBreaker(config -> config
+ .setStatusCodes(codeSets)
+ .setFallbackUri("forward:/fallback")
+ ))
+ .uri(httpUri))
+ .route(p -> p
+ .host("*.circuitbreaker-no-fallback.com")
+ .filters(f -> f
+ .circuitBreaker(config -> config
+ .setStatusCodes(codeSets)
+ ))
+ .uri(httpUri))
+ .build();
+ }
+
+ @RestController
+ static class Controller {
+ @RequestMapping("/fallback")
+ public Mono fallback() {
+ return Mono.just("fallback");
+ }
+ }
+
+ }
+
+}
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerMockServerTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerMockServerTest.java
new file mode 100644
index 000000000..e8315c2e7
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerMockServerTest.java
@@ -0,0 +1,149 @@
+/*
+ * 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.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import com.google.protobuf.util.JsonFormat;
+import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
+import com.tencent.polaris.api.config.Configuration;
+import com.tencent.polaris.api.pojo.ServiceKey;
+import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI;
+import com.tencent.polaris.circuitbreak.factory.CircuitBreakAPIFactory;
+import com.tencent.polaris.client.util.Utils;
+import com.tencent.polaris.specification.api.v1.fault.tolerance.CircuitBreakerProto;
+import com.tencent.polaris.test.common.TestUtils;
+import com.tencent.polaris.test.mock.discovery.NamingServer;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import org.springframework.cloud.client.circuitbreaker.CircuitBreaker;
+import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreaker;
+
+import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST;
+import static com.tencent.polaris.test.common.Consts.SERVICE_CIRCUIT_BREAKER;
+import static com.tencent.polaris.test.common.TestUtils.SERVER_ADDRESS_ENV;
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Test for {@link PolarisCircuitBreaker} and {@link ReactivePolarisCircuitBreaker} using real mock server.
+ *
+ * @author sean yu
+ */
+@ExtendWith(MockitoExtension.class)
+public class PolarisCircuitBreakerMockServerTest {
+
+ private static MockedStatic mockedApplicationContextAwareUtils;
+ private static NamingServer namingServer;
+
+ @BeforeAll
+ public static void beforeAll() throws IOException {
+ mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class);
+ mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties("spring.cloud.polaris.namespace"))
+ .thenReturn(NAMESPACE_TEST);
+ mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties("spring.cloud.polaris.service"))
+ .thenReturn(SERVICE_CIRCUIT_BREAKER);
+
+ try {
+ namingServer = NamingServer.startNamingServer(-1);
+ System.setProperty(SERVER_ADDRESS_ENV, String.format("127.0.0.1:%d", namingServer.getPort()));
+ }
+ catch (IOException e) {
+
+ }
+ ServiceKey serviceKey = new ServiceKey(NAMESPACE_TEST, SERVICE_CIRCUIT_BREAKER);
+
+ CircuitBreakerProto.CircuitBreakerRule.Builder circuitBreakerRuleBuilder = CircuitBreakerProto.CircuitBreakerRule.newBuilder();
+ InputStream inputStream = PolarisCircuitBreakerMockServerTest.class.getClassLoader().getResourceAsStream("circuitBreakerRule.json");
+ String json = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).lines().collect(Collectors.joining(""));
+ JsonFormat.parser().ignoringUnknownFields().merge(json, circuitBreakerRuleBuilder);
+ CircuitBreakerProto.CircuitBreakerRule circuitBreakerRule = circuitBreakerRuleBuilder.build();
+ CircuitBreakerProto.CircuitBreaker circuitBreaker = CircuitBreakerProto.CircuitBreaker.newBuilder().addRules(circuitBreakerRule).build();
+ namingServer.getNamingService().setCircuitBreaker(serviceKey, circuitBreaker);
+ }
+
+ @AfterAll
+ public static void afterAll() {
+ if (null != namingServer) {
+ namingServer.terminate();
+ }
+ }
+
+ @Test
+ public void testCircuitBreaker() {
+ Configuration configuration = TestUtils.configWithEnvAddress();
+ CircuitBreakAPI circuitBreakAPI = CircuitBreakAPIFactory.createCircuitBreakAPIByConfig(configuration);
+
+ PolarisCircuitBreakerFactory polarisCircuitBreakerFactory = new PolarisCircuitBreakerFactory(circuitBreakAPI);
+ CircuitBreaker cb = polarisCircuitBreakerFactory.create(SERVICE_CIRCUIT_BREAKER);
+
+ // trigger fallback for 5 times
+ List resList = new ArrayList<>();
+ for (int i = 0; i < 5; i++) {
+ int finalI = i;
+ String res = cb.run(() -> {
+ if (finalI % 2 == 1) {
+ throw new IllegalArgumentException("invoke failed");
+ }
+ else {
+ return "invoke success";
+ }
+ }, t -> "fallback");
+ resList.add(res);
+ Utils.sleepUninterrupted(1000);
+ }
+ assertThat(resList).isEqualTo(Arrays.asList("invoke success", "fallback", "fallback", "fallback", "fallback"));
+
+ // always fallback
+ ReactivePolarisCircuitBreakerFactory reactivePolarisCircuitBreakerFactory = new ReactivePolarisCircuitBreakerFactory(circuitBreakAPI);
+ ReactiveCircuitBreaker rcb = reactivePolarisCircuitBreakerFactory.create(SERVICE_CIRCUIT_BREAKER);
+
+ assertThat(Mono.just("foobar").transform(it -> rcb.run(it, t -> Mono.just("fallback")))
+ .block()).isEqualTo("fallback");
+
+ assertThat(Mono.error(new RuntimeException("boom")).transform(it -> rcb.run(it, t -> Mono.just("fallback")))
+ .block()).isEqualTo("fallback");
+
+ assertThat(Flux.just("foobar", "hello world").transform(it -> rcb.run(it, t -> Flux.just("fallback", "fallback")))
+ .collectList().block())
+ .isEqualTo(Arrays.asList("fallback", "fallback"));
+
+ assertThat(Flux.error(new RuntimeException("boom")).transform(it -> rcb.run(it, t -> Flux.just("fallback")))
+ .collectList().block())
+ .isEqualTo(Collections.singletonList("fallback"));
+
+
+ }
+
+}
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
new file mode 100644
index 000000000..bf35fa8f9
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerTest.java
@@ -0,0 +1,101 @@
+/*
+ * 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.common.util.ApplicationContextAwareUtils;
+import com.tencent.cloud.polaris.circuitbreaker.common.PolarisCircuitBreakerConfigBuilder;
+import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerAutoConfiguration;
+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 org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import org.springframework.boot.autoconfigure.AutoConfigurations;
+import org.springframework.boot.test.context.runner.ApplicationContextRunner;
+import org.springframework.cloud.client.circuitbreaker.CircuitBreaker;
+import org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration;
+
+import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST;
+import static com.tencent.polaris.test.common.Consts.SERVICE_CIRCUIT_BREAKER;
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Test for {@link PolarisCircuitBreaker}.
+ *
+ * @author sean yu
+ */
+@ExtendWith(MockitoExtension.class)
+public class PolarisCircuitBreakerTest {
+
+ private static ApplicationContextRunner contextRunner = new ApplicationContextRunner()
+ .withConfiguration(AutoConfigurations.of(
+ PolarisContextAutoConfiguration.class,
+ RpcEnhancementAutoConfiguration.class,
+ LoadBalancerAutoConfiguration.class,
+ PolarisCircuitBreakerFeignClientAutoConfiguration.class,
+ PolarisCircuitBreakerAutoConfiguration.class))
+ .withPropertyValues("spring.cloud.polaris.circuitbreaker.enabled=true");
+
+ private static MockedStatic mockedApplicationContextAwareUtils;
+
+ @BeforeAll
+ public static void beforeClass() {
+ mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class);
+ mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties("spring.cloud.polaris.namespace"))
+ .thenReturn(NAMESPACE_TEST);
+ mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties("spring.cloud.polaris.service"))
+ .thenReturn(SERVICE_CIRCUIT_BREAKER);
+ }
+
+ @AfterAll
+ public static void afterAll() {
+ mockedApplicationContextAwareUtils.close();
+ }
+
+ @Test
+ public void run() {
+ this.contextRunner.run(context -> {
+
+ PolarisCircuitBreakerFactory polarisCircuitBreakerFactory = context.getBean(PolarisCircuitBreakerFactory.class);
+ CircuitBreaker cb = polarisCircuitBreakerFactory.create(SERVICE_CIRCUIT_BREAKER);
+
+ PolarisCircuitBreakerConfigBuilder.PolarisCircuitBreakerConfiguration configuration =
+ polarisCircuitBreakerFactory.configBuilder(SERVICE_CIRCUIT_BREAKER).build();
+
+ polarisCircuitBreakerFactory.configureDefault(id -> configuration);
+
+ assertThat(cb.run(() -> "foobar")).isEqualTo("foobar");
+
+ assertThat((String) cb.run(() -> {
+ throw new RuntimeException("boom");
+ }, t -> "fallback")).isEqualTo("fallback");
+
+ });
+ }
+
+
+
+
+}
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/ReactivePolarisCircuitBreakerTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/ReactivePolarisCircuitBreakerTest.java
new file mode 100644
index 000000000..f06502c87
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/ReactivePolarisCircuitBreakerTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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.Arrays;
+import java.util.Collections;
+
+import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
+import com.tencent.cloud.polaris.circuitbreaker.common.PolarisCircuitBreakerConfigBuilder;
+import com.tencent.cloud.polaris.circuitbreaker.config.ReactivePolarisCircuitBreakerAutoConfiguration;
+import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration;
+import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementAutoConfiguration;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import org.springframework.boot.autoconfigure.AutoConfigurations;
+import org.springframework.boot.test.context.runner.ApplicationContextRunner;
+import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreaker;
+import org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration;
+
+import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST;
+import static com.tencent.polaris.test.common.Consts.SERVICE_CIRCUIT_BREAKER;
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Test for {@link ReactivePolarisCircuitBreaker}.
+ *
+ * @author sean yu
+ */
+@ExtendWith(MockitoExtension.class)
+public class ReactivePolarisCircuitBreakerTest {
+
+ private final ApplicationContextRunner reactiveContextRunner = new ApplicationContextRunner()
+ .withConfiguration(AutoConfigurations.of(
+ PolarisContextAutoConfiguration.class,
+ RpcEnhancementAutoConfiguration.class,
+ LoadBalancerAutoConfiguration.class,
+ ReactivePolarisCircuitBreakerAutoConfiguration.class))
+ .withPropertyValues("spring.cloud.polaris.circuitbreaker.enabled=true");
+
+ private static MockedStatic mockedApplicationContextAwareUtils;
+
+ @BeforeAll
+ public static void beforeClass() {
+ mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class);
+ mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties("spring.cloud.polaris.namespace"))
+ .thenReturn(NAMESPACE_TEST);
+ mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties("spring.cloud.polaris.service"))
+ .thenReturn(SERVICE_CIRCUIT_BREAKER);
+ }
+
+ @AfterAll
+ public static void afterAll() {
+ mockedApplicationContextAwareUtils.close();
+ }
+
+ @Test
+ public void run() {
+ this.reactiveContextRunner.run(context -> {
+ ReactivePolarisCircuitBreakerFactory polarisCircuitBreakerFactory = context.getBean(ReactivePolarisCircuitBreakerFactory.class);
+ ReactiveCircuitBreaker cb = polarisCircuitBreakerFactory.create(SERVICE_CIRCUIT_BREAKER);
+
+ PolarisCircuitBreakerConfigBuilder.PolarisCircuitBreakerConfiguration configuration =
+ polarisCircuitBreakerFactory.configBuilder(SERVICE_CIRCUIT_BREAKER).build();
+
+ polarisCircuitBreakerFactory.configureDefault(id -> configuration);
+
+ assertThat(Mono.just("foobar").transform(cb::run).block()).isEqualTo("foobar");
+
+ assertThat(Mono.error(new RuntimeException("boom")).transform(it -> cb.run(it, t -> Mono.just("fallback")))
+ .block()).isEqualTo("fallback");
+
+ assertThat(Flux.just("foobar", "hello world").transform(cb::run).collectList().block())
+ .isEqualTo(Arrays.asList("foobar", "hello world"));
+
+ assertThat(Flux.error(new RuntimeException("boom")).transform(it -> cb.run(it, t -> Flux.just("fallback")))
+ .collectList().block()).isEqualTo(Collections.singletonList("fallback"));
+ });
+ }
+
+}
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
deleted file mode 100644
index f1dcf17a7..000000000
--- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerAutoConfigurationTest.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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 com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration;
-import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementAutoConfiguration;
-import org.junit.jupiter.api.Test;
-
-import org.springframework.boot.autoconfigure.AutoConfigurations;
-import org.springframework.boot.test.context.runner.ApplicationContextRunner;
-import org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-/**
- * Test for {@link PolarisCircuitBreakerAutoConfiguration}.
- *
- * @author Haotian Zhang
- */
-public class PolarisCircuitBreakerAutoConfigurationTest {
- private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
- .withConfiguration(AutoConfigurations.of(
- PolarisContextAutoConfiguration.class,
- RpcEnhancementAutoConfiguration.class,
- LoadBalancerAutoConfiguration.class,
- RpcEnhancementAutoConfiguration.class,
- PolarisCircuitBreakerAutoConfiguration.class))
- .withPropertyValues("spring.cloud.polaris.circuitbreaker.enabled=true");
-
- @Test
- public void testDefaultInitialization() {
- this.contextRunner.run(context -> {
- assertThat(context).hasSingleBean(
- PolarisCircuitBreakerAutoConfiguration.CircuitBreakerConfigModifier.class);
- });
- }
-}
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/resources/application-test-gateway.yml b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/resources/application-test-gateway.yml
new file mode 100644
index 000000000..6094b46e5
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/resources/application-test-gateway.yml
@@ -0,0 +1,36 @@
+spring:
+ application:
+ name: GatewayScgService
+ cloud:
+ tencent:
+ plugin:
+ scg:
+ staining:
+ enabled: true
+ rule-staining:
+ enabled: true
+ router:
+ feature-env:
+ enabled: true
+ polaris:
+ address: grpc://127.0.0.1:8091
+ namespace: default
+ enabled: true
+ gateway:
+ routes:
+ - id: cb-test
+ uri: http://localhost:${server.port}/hello/1
+ predicates:
+ - Path=/cb-test/**
+ filters:
+ - name: CircuitBreaker
+ args:
+ statusCodes: 5**,4**,3**,2**,1**,500,400
+ fallbackUri: forward:/polaris-fallback
+logging:
+ level:
+ root: info
+ com.tencent.polaris.discovery.client.flow.RegisterFlow: off
+ com.tencent.polaris.plugins.registry.memory.CacheObject: off
+ com.tencent.cloud.polaris.circuitbreaker: debug
+
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/resources/circuitBreakerRule.json b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/resources/circuitBreakerRule.json
new file mode 100644
index 000000000..0a1e97f2a
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/resources/circuitBreakerRule.json
@@ -0,0 +1,59 @@
+{
+ "@type": "type.googleapis.com/v1.CircuitBreakerRule",
+ "id": "5f1601f01823474d9be39c0bbb26ab87",
+ "name": "test",
+ "namespace": "TestCircuitBreakerRule",
+ "enable": true,
+ "revision": "10b120c08706429f8fdc3fb44a53224b",
+ "ctime": "1754-08-31 06:49:24",
+ "mtime": "2023-02-21 17:35:31",
+ "etime": "",
+ "description": "",
+ "level": "SERVICE",
+ "ruleMatcher": {
+ "source": {
+ "service": "*",
+ "namespace": "*"
+ },
+ "destination": {
+ "service": "*",
+ "namespace": "*",
+ "method": null
+ }
+ },
+ "errorConditions": [
+ {
+ "inputType": "RET_CODE",
+ "condition": {
+ "type": "NOT_EQUALS",
+ "value": "200",
+ "valueType": "TEXT"
+ }
+ }
+ ],
+ "triggerCondition": [
+ {
+ "triggerType": "CONSECUTIVE_ERROR",
+ "errorCount": 1,
+ "errorPercent": 1,
+ "interval": 5,
+ "minimumRequest": 5
+ }
+ ],
+ "maxEjectionPercent": 0,
+ "recoverCondition": {
+ "sleepWindow": 60,
+ "consecutiveSuccess": 3
+ },
+ "faultDetectConfig": {
+ "enable": true
+ },
+ "fallbackConfig": {
+ "enable": false,
+ "response": {
+ "code": 0,
+ "headers": [],
+ "body": ""
+ }
+ }
+}
\ No newline at end of file
diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-b/pom.xml b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-callee-service/pom.xml
similarity index 92%
rename from spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-b/pom.xml
rename to spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-callee-service/pom.xml
index 06bb41d0f..d26bbbf42 100644
--- a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-b/pom.xml
+++ b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-callee-service/pom.xml
@@ -10,8 +10,8 @@
4.0.0
- polaris-circuitbreaker-example-b
- Polaris Circuit Breaker Example B
+ polaris-circuitbreaker-callee-service
+ Polaris Circuit Breaker Callee Example
diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-b/src/main/java/com/tencent/cloud/polaris/circuitbreaker/example/ServiceB.java b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-callee-service/src/main/java/com/tencent/cloud/polaris/circuitbreaker/example/ServiceB.java
similarity index 100%
rename from spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-b/src/main/java/com/tencent/cloud/polaris/circuitbreaker/example/ServiceB.java
rename to spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-callee-service/src/main/java/com/tencent/cloud/polaris/circuitbreaker/example/ServiceB.java
diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-b/src/main/java/com/tencent/cloud/polaris/circuitbreaker/example/ServiceBController.java b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-callee-service/src/main/java/com/tencent/cloud/polaris/circuitbreaker/example/ServiceBController.java
similarity index 100%
rename from spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-b/src/main/java/com/tencent/cloud/polaris/circuitbreaker/example/ServiceBController.java
rename to spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-callee-service/src/main/java/com/tencent/cloud/polaris/circuitbreaker/example/ServiceBController.java
diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-b/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-callee-service/src/main/resources/bootstrap.yml
similarity index 81%
rename from spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-b/src/main/resources/bootstrap.yml
rename to spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-callee-service/src/main/resources/bootstrap.yml
index d6945b5b4..5fa99c252 100644
--- a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-b/src/main/resources/bootstrap.yml
+++ b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-callee-service/src/main/resources/bootstrap.yml
@@ -2,7 +2,7 @@ server:
port: 48081
spring:
application:
- name: polaris-circuitbreaker-example-b
+ name: polaris-circuitbreaker-callee-service
cloud:
polaris:
address: grpc://183.47.111.80:8091
diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-b2/pom.xml b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-callee-service2/pom.xml
similarity index 92%
rename from spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-b2/pom.xml
rename to spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-callee-service2/pom.xml
index 2c941eced..204331a2a 100644
--- a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-b2/pom.xml
+++ b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-callee-service2/pom.xml
@@ -10,7 +10,8 @@
4.0.0
- polaris-circuitbreaker-example-b2
+ polaris-circuitbreaker-callee-service2
+ Polaris Circuit Breaker Callee Example 2
diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-b2/src/main/java/com/tencent/cloud/polaris/ciruitbreaker/example/ServiceB2.java b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-callee-service2/src/main/java/com/tencent/cloud/polaris/ciruitbreaker/example/ServiceB2.java
similarity index 100%
rename from spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-b2/src/main/java/com/tencent/cloud/polaris/ciruitbreaker/example/ServiceB2.java
rename to spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-callee-service2/src/main/java/com/tencent/cloud/polaris/ciruitbreaker/example/ServiceB2.java
diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-b2/src/main/java/com/tencent/cloud/polaris/ciruitbreaker/example/ServiceBController.java b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-callee-service2/src/main/java/com/tencent/cloud/polaris/ciruitbreaker/example/ServiceBController.java
similarity index 100%
rename from spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-b2/src/main/java/com/tencent/cloud/polaris/ciruitbreaker/example/ServiceBController.java
rename to spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-callee-service2/src/main/java/com/tencent/cloud/polaris/ciruitbreaker/example/ServiceBController.java
diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-b2/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-callee-service2/src/main/resources/bootstrap.yml
similarity index 81%
rename from spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-b2/src/main/resources/bootstrap.yml
rename to spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-callee-service2/src/main/resources/bootstrap.yml
index 5ef89145c..54cb21355 100644
--- a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-b2/src/main/resources/bootstrap.yml
+++ b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-callee-service2/src/main/resources/bootstrap.yml
@@ -2,7 +2,7 @@ server:
port: 48082
spring:
application:
- name: polaris-circuitbreaker-example-b
+ name: polaris-circuitbreaker-callee-service
cloud:
polaris:
address: grpc://183.47.111.80:8091
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
deleted file mode 100644
index de8c607b2..000000000
--- a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/src/main/resources/bootstrap.yml
+++ /dev/null
@@ -1,38 +0,0 @@
-server:
- port: 48080
-spring:
- application:
- name: polaris-circuitbreaker-example-a
- cloud:
- polaris:
- address: grpc://183.47.111.80:8091
- namespace: default
- enabled: true
- circuitbreaker:
- enabled: true
- stat:
- enabled: true
- port: 28081
- loadbalancer:
- configurations: polaris
- tencent:
- rpc-enhancement:
- enabled: true
- reporter:
- ignore-internal-server-error: true
- series: server_error
- statuses: gateway_timeout, bad_gateway, service_unavailable
-
-feign:
- circuitbreaker:
- enabled: true
- compression:
- request:
- enabled: false
- mime-types: text/xml,application/xml,application/json
- min-request-size: 2048
- response:
- enabled: false
-
-serivceB:
- url: http://localhost:48081
diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/pom.xml b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-feign-example/pom.xml
similarity index 88%
rename from spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/pom.xml
rename to spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-feign-example/pom.xml
index 6811c6230..6f7382e7b 100644
--- a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/pom.xml
+++ b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-feign-example/pom.xml
@@ -10,8 +10,8 @@
4.0.0
- polaris-circuitbreaker-example-a
- Polaris Circuit Breaker Example A
+ polaris-circuitbreaker-feign-example
+ Polaris Circuit Breaker Feign Example
@@ -24,11 +24,6 @@
spring-cloud-starter-tencent-polaris-discovery
-
- com.tencent.cloud
- spring-cloud-starter-tencent-polaris-circuitbreaker
-
-
org.springframework.cloud
spring-cloud-starter-openfeign
@@ -40,8 +35,8 @@
- org.springframework.cloud
- spring-cloud-circuitbreaker-spring-retry
+ com.tencent.cloud
+ spring-cloud-starter-tencent-polaris-circuitbreaker
diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/src/main/java/com/tencent/cloud/polaris/circuitbreaker/example/ProviderB.java b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-feign-example/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/example/ProviderB.java
similarity index 81%
rename from spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/src/main/java/com/tencent/cloud/polaris/circuitbreaker/example/ProviderB.java
rename to spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-feign-example/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/example/ProviderB.java
index f0c05217a..5e1160877 100644
--- a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/src/main/java/com/tencent/cloud/polaris/circuitbreaker/example/ProviderB.java
+++ b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-feign-example/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/example/ProviderB.java
@@ -15,17 +15,19 @@
* specific language governing permissions and limitations under the License.
*/
-package com.tencent.cloud.polaris.circuitbreaker.example;
+package com.tencent.cloud.polaris.circuitbreaker.feign.example;
import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.context.annotation.Primary;
import org.springframework.web.bind.annotation.GetMapping;
/**
* Circuit breaker example callee provider.
*
- * @author Haotian Zhang
+ * @author sean yu
*/
-@FeignClient(name = "polaris-circuitbreaker-example-b", fallback = ProviderBFallback.class)
+@Primary
+@FeignClient(name = "polaris-circuitbreaker-callee-service", fallback = ProviderBFallback.class)
public interface ProviderB {
/**
diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/src/main/java/com/tencent/cloud/polaris/circuitbreaker/example/ProviderBFallback.java b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-feign-example/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/example/ProviderBFallback.java
similarity index 87%
rename from spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/src/main/java/com/tencent/cloud/polaris/circuitbreaker/example/ProviderBFallback.java
rename to spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-feign-example/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/example/ProviderBFallback.java
index bf47d49dd..e62cbf24c 100644
--- a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/src/main/java/com/tencent/cloud/polaris/circuitbreaker/example/ProviderBFallback.java
+++ b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-feign-example/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/example/ProviderBFallback.java
@@ -15,20 +15,20 @@
* specific language governing permissions and limitations under the License.
*/
-package com.tencent.cloud.polaris.circuitbreaker.example;
+package com.tencent.cloud.polaris.circuitbreaker.feign.example;
import org.springframework.stereotype.Component;
/**
* Circuit breaker example callee fallback.
*
- * @author Haotian Zhang
+ * @author sean yu
*/
@Component
public class ProviderBFallback implements ProviderB {
@Override
public String info() {
- return "trigger the refuse for service b";
+ return "fallback: trigger the refuse for service b";
}
}
diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/src/main/java/com/tencent/cloud/polaris/circuitbreaker/example/ServiceAController.java b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-feign-example/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/example/ServiceAController.java
similarity index 64%
rename from spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/src/main/java/com/tencent/cloud/polaris/circuitbreaker/example/ServiceAController.java
rename to spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-feign-example/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/example/ServiceAController.java
index 79ba2c0ef..5c7108716 100644
--- a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/src/main/java/com/tencent/cloud/polaris/circuitbreaker/example/ServiceAController.java
+++ b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-feign-example/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/example/ServiceAController.java
@@ -15,19 +15,18 @@
* specific language governing permissions and limitations under the License.
*/
-package com.tencent.cloud.polaris.circuitbreaker.example;
+package com.tencent.cloud.polaris.circuitbreaker.feign.example;
+
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
-import org.springframework.web.client.RestTemplate;
/**
* Circuit breaker example caller controller.
*
- * @author Haotian Zhang
+ * @author sean yu
*/
@RestController
@RequestMapping("/example/service/a")
@@ -36,9 +35,6 @@ public class ServiceAController {
@Autowired
private ProviderB polarisServiceB;
- @Autowired
- private RestTemplate restTemplate;
-
/**
* Get info of Service B by Feign.
* @return info of Service B
@@ -48,20 +44,4 @@ public class ServiceAController {
return polarisServiceB.info();
}
- @GetMapping("/getBServiceInfoByRestTemplate")
- public String getBServiceInfoByRestTemplate() {
- return restTemplate.getForObject("http://polaris-circuitbreaker-example-b/example/service/b/info", String.class);
- }
-
- /**
- * Get info of Service B by RestTemplate.
- * @return info of Service B
- */
- @GetMapping("/testRest")
- public String testRest() {
- ResponseEntity entity = restTemplate.getForEntity(
- "http://polaris-circuitbreaker-example-b/example/service/b/info",
- String.class);
- return entity.getBody();
- }
}
diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-feign-example/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/example/ServiceAFeign.java b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-feign-example/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/example/ServiceAFeign.java
new file mode 100644
index 000000000..f6a012bb0
--- /dev/null
+++ b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-feign-example/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/example/ServiceAFeign.java
@@ -0,0 +1,38 @@
+/*
+ * 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.feign.example;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+
+/**
+ * Circuit breaker example caller application.
+ *
+ * @author sean yu
+ */
+@SpringBootApplication
+@EnableFeignClients
+public class ServiceAFeign {
+
+ public static void main(String[] args) {
+ SpringApplication.run(ServiceAFeign.class, args);
+ }
+
+}
diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-feign-example/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-feign-example/src/main/resources/bootstrap.yml
new file mode 100644
index 000000000..3378ae635
--- /dev/null
+++ b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-feign-example/src/main/resources/bootstrap.yml
@@ -0,0 +1,39 @@
+server:
+ port: 48080
+spring:
+ application:
+ name: polaris-circuitbreaker-feign-example
+ cloud:
+ polaris:
+ address: grpc://183.47.111.80:8091
+ namespace: default
+ enabled: true
+ loadbalancer:
+ enabled: true
+ circuitbreaker:
+ enabled: true
+# stat:
+# enabled: true
+# port: 28081
+# tencent:
+# rpc-enhancement:
+# enabled: true
+# reporter:
+# ignore-internal-server-error: true
+# series: server_error
+# statuses: gateway_timeout, bad_gateway, service_unavailable
+
+feign:
+ circuitbreaker:
+ enabled: true
+# compression:
+# request:
+# enabled: false
+# mime-types: text/xml,application/xml,application/json
+# min-request-size: 2048
+
+logging:
+ level:
+ root: info
+ com.tencent.cloud: debug
+
diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-gateway-example/pom.xml b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-gateway-example/pom.xml
new file mode 100644
index 000000000..9064f5b88
--- /dev/null
+++ b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-gateway-example/pom.xml
@@ -0,0 +1,87 @@
+
+
+
+ polaris-circuitbreaker-example
+ com.tencent.cloud
+ ${revision}
+ ../pom.xml
+
+ 4.0.0
+
+ polaris-circuitbreaker-gateway-example
+ Polaris Circuit Breaker Gateway Example
+
+
+
+ spring-cloud-starter-tencent-polaris-discovery
+ com.tencent.cloud
+
+
+
+ com.tencent.cloud
+ spring-cloud-starter-tencent-polaris-circuitbreaker
+
+
+
+ com.tencent.cloud
+ spring-cloud-starter-tencent-polaris-router
+
+
+
+ com.tencent.cloud
+ spring-cloud-tencent-gateway-plugin
+
+
+
+ com.tencent.cloud
+ spring-cloud-starter-tencent-metadata-transfer
+
+
+
+ com.tencent.cloud
+ spring-cloud-tencent-featureenv-plugin
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-gateway
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-bootstrap
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ repackage
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+ 3.2.0
+
+
+ attach-sources
+
+ jar
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-gateway-example/src/main/java/com/tencent/cloud/polaris/circuitbreaker/gateway/example/FallbackController.java b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-gateway-example/src/main/java/com/tencent/cloud/polaris/circuitbreaker/gateway/example/FallbackController.java
new file mode 100644
index 000000000..c0d964b56
--- /dev/null
+++ b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-gateway-example/src/main/java/com/tencent/cloud/polaris/circuitbreaker/gateway/example/FallbackController.java
@@ -0,0 +1,37 @@
+/*
+ * 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.gateway.example;
+
+import reactor.core.publisher.Mono;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * FallbackController.
+ *
+ * sean yu
+ */
+@RestController
+public class FallbackController {
+
+ @GetMapping("/polaris-fallback")
+ Mono getFallback() {
+ return Mono.just("fallback: trigger the refuse for service b");
+ }
+}
diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-gateway-example/src/main/java/com/tencent/cloud/polaris/circuitbreaker/gateway/example/GatewayScgApplication.java b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-gateway-example/src/main/java/com/tencent/cloud/polaris/circuitbreaker/gateway/example/GatewayScgApplication.java
new file mode 100644
index 000000000..ea042b2f9
--- /dev/null
+++ b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-gateway-example/src/main/java/com/tencent/cloud/polaris/circuitbreaker/gateway/example/GatewayScgApplication.java
@@ -0,0 +1,35 @@
+/*
+ * 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.gateway.example;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * SCG application.
+ *
+ * @author sean yu
+ */
+@SpringBootApplication
+public class GatewayScgApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(GatewayScgApplication.class, args);
+ }
+
+}
diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-gateway-example/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-gateway-example/src/main/resources/bootstrap.yml
new file mode 100644
index 000000000..399af3ca1
--- /dev/null
+++ b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-gateway-example/src/main/resources/bootstrap.yml
@@ -0,0 +1,57 @@
+server:
+ session-timeout: 1800
+ port: 48080
+spring:
+ application:
+ name: GatewayScgService
+ cloud:
+ tencent:
+ plugin:
+ scg:
+ staining:
+ enabled: true
+ rule-staining:
+ enabled: true
+ router:
+ feature-env:
+ enabled: true
+ polaris:
+ address: grpc://183.47.111.80:8091
+ namespace: default
+ enabled: true
+ gateway:
+ discovery:
+ locator:
+ enabled: true
+ 'predicates[0]':
+ name: Path
+ args:
+ patterns: '''/'' + serviceId + ''/**'''
+ 'filters[0]':
+ name: RewritePath
+ args:
+ regexp: '''/'' + serviceId + ''/(?.*)'''
+ replacement: '''/$\{remaining}'''
+ 'filters[1]':
+ name: CircuitBreaker
+ args:
+ statusCodes: '''4**,502'''
+ fallbackUri: '''forward:/polaris-fallback'''
+# routes:
+# - id: polaris-circuitbreaker-callee-service
+# uri: lb://polaris-circuitbreaker-callee-service
+# predicates:
+# - Path=/polaris-circuitbreaker-callee-service/**
+# filters:
+# - StripPrefix=1
+# - name: CircuitBreaker
+# args:
+# statusCodes: 502
+# fallbackUri: forward:/polaris-fallback
+logging:
+ level:
+ root: info
+ com.tencent.polaris.discovery.client.flow.RegisterFlow: off
+ com.tencent.polaris.plugins.registry.memory.CacheObject: off
+ com.tencent.cloud.polaris.circuitbreaker: debug
+
diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-resttemplate-example/pom.xml b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-resttemplate-example/pom.xml
new file mode 100644
index 000000000..f86372777
--- /dev/null
+++ b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-resttemplate-example/pom.xml
@@ -0,0 +1,72 @@
+
+
+
+ polaris-circuitbreaker-example
+ com.tencent.cloud
+ ${revision}
+ ../pom.xml
+
+ 4.0.0
+
+ polaris-circuitbreaker-resttemplate-example
+ Polaris Circuit Breaker RestTemplate Example
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ com.tencent.cloud
+ spring-cloud-starter-tencent-polaris-discovery
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-loadbalancer
+
+
+
+ com.tencent.cloud
+ spring-cloud-starter-tencent-polaris-circuitbreaker
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-bootstrap
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ repackage
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+ 3.2.0
+
+
+ attach-sources
+
+ jar
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-resttemplate-example/src/main/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/example/ServiceAController.java b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-resttemplate-example/src/main/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/example/ServiceAController.java
new file mode 100644
index 000000000..d76816ed1
--- /dev/null
+++ b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-resttemplate-example/src/main/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/example/ServiceAController.java
@@ -0,0 +1,53 @@
+/*
+ * 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.resttemplate.example;
+
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * Circuit breaker example caller controller.
+ *
+ * @author sean yu
+ */
+@RestController
+@RequestMapping("/example/service/a")
+public class ServiceAController {
+
+ @Autowired
+ private RestTemplate restTemplate;
+
+ @Autowired
+ private CircuitBreakerFactory circuitBreakerFactory;
+
+ @GetMapping("/getBServiceInfo")
+ public String getBServiceInfo() {
+ return circuitBreakerFactory
+ .create("polaris-circuitbreaker-callee-service#/example/service/b/info")
+ .run(() ->
+ restTemplate.getForObject("/example/service/b/info", String.class),
+ throwable -> "trigger the refuse for service b"
+ );
+ }
+
+}
diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-resttemplate-example/src/main/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/example/ServiceAResTemplate.java b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-resttemplate-example/src/main/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/example/ServiceAResTemplate.java
new file mode 100644
index 000000000..21e2f4778
--- /dev/null
+++ b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-resttemplate-example/src/main/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/example/ServiceAResTemplate.java
@@ -0,0 +1,49 @@
+/*
+ * 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.resttemplate.example;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.client.loadbalancer.LoadBalanced;
+import org.springframework.context.annotation.Bean;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.util.DefaultUriBuilderFactory;
+
+/**
+ * Circuit breaker example caller application.
+ *
+ * @author sean yu
+ */
+@SpringBootApplication
+public class ServiceAResTemplate {
+
+ public static void main(String[] args) {
+ SpringApplication.run(ServiceAResTemplate.class, args);
+ }
+
+ @Bean
+ @LoadBalanced
+ public RestTemplate restTemplate() {
+ DefaultUriBuilderFactory uriBuilderFactory = new DefaultUriBuilderFactory("http://polaris-circuitbreaker-callee-service");
+ RestTemplate restTemplate = new RestTemplate();
+ restTemplate.setUriTemplateHandler(uriBuilderFactory);
+ return restTemplate;
+ }
+
+}
diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-resttemplate-example/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-resttemplate-example/src/main/resources/bootstrap.yml
new file mode 100644
index 000000000..16fa8bd3b
--- /dev/null
+++ b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-resttemplate-example/src/main/resources/bootstrap.yml
@@ -0,0 +1,30 @@
+server:
+ port: 48080
+spring:
+ application:
+ name: polaris-circuitbreaker-resttemplate-example
+ cloud:
+ polaris:
+ address: grpc://183.47.111.80:8091
+ namespace: default
+ enabled: true
+ loadbalancer:
+ enabled: true
+ circuitbreaker:
+ enabled: true
+# stat:
+# enabled: true
+# port: 28081
+# tencent:
+# rpc-enhancement:
+# enabled: true
+# reporter:
+# ignore-internal-server-error: true
+# series: server_error
+# statuses: gateway_timeout, bad_gateway, service_unavailable
+
+logging:
+ level:
+ root: info
+ com.tencent.cloud: debug
+
diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-webclient-example/pom.xml b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-webclient-example/pom.xml
new file mode 100644
index 000000000..3305c2c58
--- /dev/null
+++ b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-webclient-example/pom.xml
@@ -0,0 +1,72 @@
+
+
+
+ polaris-circuitbreaker-example
+ com.tencent.cloud
+ ${revision}
+ ../pom.xml
+
+ 4.0.0
+
+ polaris-circuitbreaker-webclient-example
+ Polaris Circuit Breaker WebClient Example
+
+
+
+ org.springframework.boot
+ spring-boot-starter-webflux
+
+
+
+ com.tencent.cloud
+ spring-cloud-starter-tencent-polaris-discovery
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-loadbalancer
+
+
+
+ com.tencent.cloud
+ spring-cloud-starter-tencent-polaris-circuitbreaker
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-bootstrap
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ repackage
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+ 3.2.0
+
+
+ attach-sources
+
+ jar
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-webclient-example/src/main/java/com/tencent/cloud/polaris/circuitbreaker/webclient/example/ServiceAController.java b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-webclient-example/src/main/java/com/tencent/cloud/polaris/circuitbreaker/webclient/example/ServiceAController.java
new file mode 100644
index 000000000..72f3c80d5
--- /dev/null
+++ b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-webclient-example/src/main/java/com/tencent/cloud/polaris/circuitbreaker/webclient/example/ServiceAController.java
@@ -0,0 +1,59 @@
+/*
+ * 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.webclient.example;
+
+import reactor.core.publisher.Mono;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreakerFactory;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.reactive.function.client.WebClient;
+
+/**
+ * Circuit breaker example caller controller.
+ *
+ * @author sean yu
+ */
+@RestController
+@RequestMapping("/example/service/a")
+public class ServiceAController {
+
+ @Autowired
+ private ReactiveCircuitBreakerFactory reactiveCircuitBreakerFactory;
+
+ @Autowired
+ private WebClient.Builder webClientBuilder;
+
+ @GetMapping("/getBServiceInfo")
+ public Mono getBServiceInfo() {
+ return webClientBuilder
+ .build()
+ .get()
+ .uri("/example/service/b/info")
+ .retrieve()
+ .bodyToMono(String.class)
+ .transform(it ->
+ reactiveCircuitBreakerFactory
+ .create("polaris-circuitbreaker-callee-service#/example/service/b/info")
+ .run(it, throwable -> Mono.just("fallback: trigger the refuse for service b"))
+ );
+ }
+
+}
diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/src/main/java/com/tencent/cloud/polaris/circuitbreaker/example/ServiceA.java b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-webclient-example/src/main/java/com/tencent/cloud/polaris/circuitbreaker/webclient/example/ServiceAWebClient.java
similarity index 75%
rename from spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/src/main/java/com/tencent/cloud/polaris/circuitbreaker/example/ServiceA.java
rename to spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-webclient-example/src/main/java/com/tencent/cloud/polaris/circuitbreaker/webclient/example/ServiceAWebClient.java
index 3db7df8f3..8104ae873 100644
--- a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/src/main/java/com/tencent/cloud/polaris/circuitbreaker/example/ServiceA.java
+++ b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-webclient-example/src/main/java/com/tencent/cloud/polaris/circuitbreaker/webclient/example/ServiceAWebClient.java
@@ -16,31 +16,30 @@
*
*/
-package com.tencent.cloud.polaris.circuitbreaker.example;
+package com.tencent.cloud.polaris.circuitbreaker.webclient.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
-import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
-import org.springframework.web.client.RestTemplate;
+import org.springframework.web.reactive.function.client.WebClient;
/**
* Circuit breaker example caller application.
*
- * @author Haotian Zhang
+ * @author sean yu
*/
@SpringBootApplication
-@EnableFeignClients
-public class ServiceA {
+public class ServiceAWebClient {
public static void main(String[] args) {
- SpringApplication.run(ServiceA.class, args);
+ SpringApplication.run(ServiceAWebClient.class, args);
}
- @Bean
@LoadBalanced
- public RestTemplate restTemplate() {
- return new RestTemplate();
+ @Bean
+ WebClient.Builder webClientBuilder() {
+ return WebClient.builder()
+ .baseUrl("http://polaris-circuitbreaker-callee-service");
}
}
diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-webclient-example/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-webclient-example/src/main/resources/bootstrap.yml
new file mode 100644
index 000000000..f84dffdea
--- /dev/null
+++ b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-webclient-example/src/main/resources/bootstrap.yml
@@ -0,0 +1,30 @@
+server:
+ port: 48080
+spring:
+ application:
+ name: polaris-circuitbreaker-webclient-example
+ cloud:
+ polaris:
+ address: grpc://183.47.111.80:8091
+ namespace: default
+ enabled: true
+ loadbalancer:
+ enabled: true
+ circuitbreaker:
+ enabled: true
+# stat:
+# enabled: true
+# port: 28081
+# tencent:
+# rpc-enhancement:
+# enabled: true
+# reporter:
+# ignore-internal-server-error: true
+# series: server_error
+# statuses: gateway_timeout, bad_gateway, service_unavailable
+
+logging:
+ level:
+ root: info
+ com.tencent.cloud: debug
+
diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/pom.xml b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/pom.xml
index 6b5daa263..8e53f8d77 100644
--- a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/pom.xml
+++ b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/pom.xml
@@ -15,8 +15,11 @@
pom
- polaris-circuitbreaker-example-a
- polaris-circuitbreaker-example-b
- polaris-circuitbreaker-example-b2
+ polaris-circuitbreaker-feign-example
+ polaris-circuitbreaker-gateway-example
+ polaris-circuitbreaker-resttemplate-example
+ polaris-circuitbreaker-webclient-example
+ polaris-circuitbreaker-callee-service
+ polaris-circuitbreaker-callee-service2