From 3f6ed5c8af04110f68910f1015ce5c93d369db2b Mon Sep 17 00:00:00 2001 From: andrew shan <45474304+andrewshan@users.noreply.github.com> Date: Wed, 28 Aug 2024 11:31:27 +0800 Subject: [PATCH] fix: fix PolarisCircuitBreakerConfiguration not clear when gateway invoke by wildcard apis (#1418) --- CHANGELOG.md | 3 +- .../PolarisCircuitBreakerFactory.java | 27 ++++++++- .../ReactivePolarisCircuitBreakerFactory.java | 26 ++++++++- ...olarisCircuitBreakerAutoConfiguration.java | 7 ++- .../PolarisCircuitBreakerProperties.java | 57 +++++++++++++++++++ ...olarisCircuitBreakerAutoConfiguration.java | 7 ++- .../util/PolarisCircuitBreakerUtils.java | 6 +- ...itional-spring-configuration-metadata.json | 9 ++- .../PolarisCircuitBreakerMockServerTest.java | 6 +- .../PolarisCircuitBreakerTest.java | 21 ++++++- .../ReactivePolarisCircuitBreakerTest.java | 20 ++++++- ...risCircuitBreakerFeignIntegrationTest.java | 6 +- ...sCircuitBreakerGatewayIntegrationTest.java | 6 +- ...uitBreakerRestTemplateIntegrationTest.java | 5 +- .../CircuitBreakerController.java | 20 +++++++ .../src/main/resources/application.yml | 2 + 16 files changed, 205 insertions(+), 23 deletions(-) create mode 100644 spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerProperties.java diff --git a/CHANGELOG.md b/CHANGELOG.md index f75209710..1942ca4c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,4 +30,5 @@ - [feat:support TSF router.](https://github.com/Tencent/spring-cloud-tencent/pull/1368) - [feat:upgrade nearby router and add namespace nearby router.](https://github.com/Tencent/spring-cloud-tencent/pull/1371) - [fix:fix contract reporting bug when using TSF.](https://github.com/Tencent/spring-cloud-tencent/pull/1373) -- [fix: fix TSF context bootstrap configuration](https://github.com/Tencent/spring-cloud-tencent/pull/1395) \ No newline at end of file +- [fix: fix TSF context bootstrap configuration](https://github.com/Tencent/spring-cloud-tencent/pull/1395) +- [fix: fix PolarisCircuitBreakerConfiguration not clear when gateway invoke by wildcard apis](https://github.com/Tencent/spring-cloud-tencent/pull/1418) \ No newline at end of file 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 index 1c789befe..331926223 100644 --- 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 @@ -17,13 +17,21 @@ package com.tencent.cloud.polaris.circuitbreaker; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import java.util.function.Function; import com.tencent.cloud.polaris.circuitbreaker.common.PolarisCircuitBreakerConfigBuilder; +import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerProperties; import com.tencent.cloud.polaris.circuitbreaker.util.PolarisCircuitBreakerUtils; import com.tencent.polaris.api.core.ConsumerAPI; +import com.tencent.polaris.api.utils.ThreadPoolUtils; import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI; +import com.tencent.polaris.client.util.NamedThreadFactory; +import org.springframework.beans.factory.DisposableBean; import org.springframework.cloud.client.circuitbreaker.CircuitBreaker; import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory; @@ -33,7 +41,7 @@ * @author seanyu 2023-02-27 */ public class PolarisCircuitBreakerFactory - extends CircuitBreakerFactory { + extends CircuitBreakerFactory implements DisposableBean { private Function defaultConfiguration = id -> { @@ -50,9 +58,19 @@ public class PolarisCircuitBreakerFactory private final ConsumerAPI consumerAPI; - public PolarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, ConsumerAPI consumerAPI) { + private final ScheduledExecutorService cleanupService = Executors.newSingleThreadScheduledExecutor( + new NamedThreadFactory("sct-circuitbreaker-cleanup", true)); + + public PolarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, ConsumerAPI consumerAPI, + PolarisCircuitBreakerProperties polarisCircuitBreakerProperties) { this.circuitBreakAPI = circuitBreakAPI; this.consumerAPI = consumerAPI; + cleanupService.scheduleWithFixedDelay( + () -> { + getConfigurations().clear(); + }, + polarisCircuitBreakerProperties.getConfigurationCleanupInterval(), + polarisCircuitBreakerProperties.getConfigurationCleanupInterval(), TimeUnit.MILLISECONDS); } @Override @@ -73,4 +91,9 @@ public void configureDefault(Function { + ReactiveCircuitBreakerFactory implements DisposableBean { private Function defaultConfiguration = id -> { @@ -49,9 +57,19 @@ public class ReactivePolarisCircuitBreakerFactory extends private final ConsumerAPI consumerAPI; - public ReactivePolarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, ConsumerAPI consumerAPI) { + private final ScheduledExecutorService cleanupService = Executors.newSingleThreadScheduledExecutor( + new NamedThreadFactory("sct-reactive-circuitbreaker-cleanup", true)); + + public ReactivePolarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, ConsumerAPI consumerAPI, + PolarisCircuitBreakerProperties polarisCircuitBreakerProperties) { this.circuitBreakAPI = circuitBreakAPI; this.consumerAPI = consumerAPI; + cleanupService.scheduleWithFixedDelay( + () -> { + getConfigurations().clear(); + }, + polarisCircuitBreakerProperties.getConfigurationCleanupInterval(), + polarisCircuitBreakerProperties.getConfigurationCleanupInterval(), TimeUnit.MILLISECONDS); } @@ -73,4 +91,8 @@ public void configureDefault( this.defaultConfiguration = defaultConfiguration; } + @Override + public void destroy() { + ThreadPoolUtils.waitAndStopThreadPools(new ExecutorService[]{cleanupService}); + } } 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 4a9ff4a4b..29523bbd0 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 @@ -33,6 +33,7 @@ import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory; import org.springframework.cloud.client.circuitbreaker.Customizer; import org.springframework.context.ApplicationContext; @@ -47,6 +48,7 @@ */ @Configuration(proxyBeanMethods = false) @ConditionalOnPolarisCircuitBreakerEnabled +@EnableConfigurationProperties(PolarisCircuitBreakerProperties.class) @AutoConfigureAfter(RpcEnhancementAutoConfiguration.class) public class PolarisCircuitBreakerAutoConfiguration { @@ -76,9 +78,10 @@ public ExceptionCircuitBreakerReporter exceptionCircuitBreakerReporter(RpcEnhanc @Bean @ConditionalOnMissingBean(CircuitBreakerFactory.class) - public CircuitBreakerFactory polarisCircuitBreakerFactory(PolarisSDKContextManager polarisSDKContextManager) { + public CircuitBreakerFactory polarisCircuitBreakerFactory(PolarisSDKContextManager polarisSDKContextManager, + PolarisCircuitBreakerProperties polarisCircuitBreakerProperties) { PolarisCircuitBreakerFactory factory = new PolarisCircuitBreakerFactory( - polarisSDKContextManager.getCircuitBreakAPI(), polarisSDKContextManager.getConsumerAPI()); + polarisSDKContextManager.getCircuitBreakAPI(), polarisSDKContextManager.getConsumerAPI(), polarisCircuitBreakerProperties); customizers.forEach(customizer -> customizer.customize(factory)); return factory; } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerProperties.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerProperties.java new file mode 100644 index 000000000..7f2680305 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerProperties.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.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * Properties of Polaris CircuitBreaker . + * + */ +@ConfigurationProperties("spring.cloud.polaris.circuitbreaker") +public class PolarisCircuitBreakerProperties { + + /** + * Whether enable polaris circuit-breaker function. + */ + @Value("${spring.cloud.polaris.circuitbreaker.enabled:#{true}}") + private boolean enabled = true; + + /** + * Interval to clean up PolarisCircuitBreakerConfiguration, unit millisecond. + */ + @Value("${spring.cloud.polaris.circuitbreaker.configuration-cleanup-interval:#{300000}}") + private long configurationCleanupInterval = 300000; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public long getConfigurationCleanupInterval() { + return configurationCleanupInterval; + } + + public void setConfigurationCleanupInterval(long configurationCleanupInterval) { + this.configurationCleanupInterval = configurationCleanupInterval; + } +} 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 index 23c3f281d..1b0f24b2f 100644 --- 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 @@ -32,6 +32,7 @@ import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.client.circuitbreaker.Customizer; import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreakerFactory; import org.springframework.context.annotation.Bean; @@ -45,6 +46,7 @@ @Configuration(proxyBeanMethods = false) @ConditionalOnClass(name = {"reactor.core.publisher.Mono", "reactor.core.publisher.Flux"}) @ConditionalOnPolarisCircuitBreakerEnabled +@EnableConfigurationProperties(PolarisCircuitBreakerProperties.class) @AutoConfigureAfter(RpcEnhancementAutoConfiguration.class) public class ReactivePolarisCircuitBreakerAutoConfiguration { @@ -67,9 +69,10 @@ public ExceptionCircuitBreakerReporter exceptionCircuitBreakerReporter(RpcEnhanc @Bean @ConditionalOnMissingBean(ReactiveCircuitBreakerFactory.class) - public ReactiveCircuitBreakerFactory polarisReactiveCircuitBreakerFactory(PolarisSDKContextManager polarisSDKContextManager) { + public ReactiveCircuitBreakerFactory polarisReactiveCircuitBreakerFactory(PolarisSDKContextManager polarisSDKContextManager, + PolarisCircuitBreakerProperties polarisCircuitBreakerProperties) { ReactivePolarisCircuitBreakerFactory factory = new ReactivePolarisCircuitBreakerFactory( - polarisSDKContextManager.getCircuitBreakAPI(), polarisSDKContextManager.getConsumerAPI()); + polarisSDKContextManager.getCircuitBreakAPI(), polarisSDKContextManager.getConsumerAPI(), polarisCircuitBreakerProperties); customizers.forEach(customizer -> customizer.customize(factory)); return factory; } 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 index 160ed96a3..352fb524f 100644 --- 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 @@ -55,12 +55,12 @@ 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]}; + 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[] {polarisCircuitBreakerMetaData[0], polarisCircuitBreakerMetaData[1], polarisCircuitBreakerMetaData[2]}; } - return new String[]{MetadataContext.LOCAL_NAMESPACE, id, ""}; + return new String[] {MetadataContext.LOCAL_NAMESPACE, id, ""}; } public static void reportStatus(ConsumerAPI consumerAPI, diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 99dc05518..2f222b999 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -3,7 +3,14 @@ { "name": "spring.cloud.polaris.circuitbreaker.enabled", "type": "java.lang.Boolean", - "defaultValue": "true" + "defaultValue": "true", + "description": "If polaris circuitbreaker enabled." + }, + { + "name": "spring.cloud.polaris.circuitbreaker.configuration-cleanup-interval", + "type": "java.lang.Long", + "defaultValue": "300000", + "description": "Interval to clean up PolarisCircuitBreakerConfiguration, unit millisecond." } ], "hints": [] 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 index 5c2c1338a..dc720bd4a 100644 --- 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 @@ -30,6 +30,7 @@ import com.google.protobuf.util.JsonFormat; import com.tencent.cloud.common.util.ApplicationContextAwareUtils; +import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerProperties; import com.tencent.cloud.polaris.context.PolarisSDKContextManager; import com.tencent.polaris.api.config.Configuration; import com.tencent.polaris.api.core.ConsumerAPI; @@ -108,7 +109,8 @@ public void testCircuitBreaker() { CircuitBreakAPI circuitBreakAPI = CircuitBreakAPIFactory.createCircuitBreakAPIByConfig(configuration); ConsumerAPI consumerAPI = DiscoveryAPIFactory.createConsumerAPIByConfig(configuration); - PolarisCircuitBreakerFactory polarisCircuitBreakerFactory = new PolarisCircuitBreakerFactory(circuitBreakAPI, consumerAPI); + PolarisCircuitBreakerProperties polarisCircuitBreakerProperties = new PolarisCircuitBreakerProperties(); + PolarisCircuitBreakerFactory polarisCircuitBreakerFactory = new PolarisCircuitBreakerFactory(circuitBreakAPI, consumerAPI, polarisCircuitBreakerProperties); CircuitBreaker cb = polarisCircuitBreakerFactory.create(SERVICE_CIRCUIT_BREAKER); // trigger fallback for 5 times @@ -129,7 +131,7 @@ public void testCircuitBreaker() { assertThat(resList).isEqualTo(Arrays.asList("invoke success", "fallback", "fallback", "fallback", "fallback")); // always fallback - ReactivePolarisCircuitBreakerFactory reactivePolarisCircuitBreakerFactory = new ReactivePolarisCircuitBreakerFactory(circuitBreakAPI, consumerAPI); + ReactivePolarisCircuitBreakerFactory reactivePolarisCircuitBreakerFactory = new ReactivePolarisCircuitBreakerFactory(circuitBreakAPI, consumerAPI, polarisCircuitBreakerProperties); ReactiveCircuitBreaker rcb = reactivePolarisCircuitBreakerFactory.create(SERVICE_CIRCUIT_BREAKER); assertThat(Mono.just("foobar").transform(it -> rcb.run(it, t -> Mono.just("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 index bf35fa8f9..47f9df697 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerTest.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerTest.java @@ -18,13 +18,19 @@ package com.tencent.cloud.polaris.circuitbreaker; +import java.lang.reflect.Method; +import java.util.Map; + import com.tencent.cloud.common.util.ApplicationContextAwareUtils; +import com.tencent.cloud.common.util.ReflectionUtils; 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 com.tencent.polaris.client.util.Utils; import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -56,7 +62,8 @@ public class PolarisCircuitBreakerTest { LoadBalancerAutoConfiguration.class, PolarisCircuitBreakerFeignClientAutoConfiguration.class, PolarisCircuitBreakerAutoConfiguration.class)) - .withPropertyValues("spring.cloud.polaris.circuitbreaker.enabled=true"); + .withPropertyValues("spring.cloud.polaris.circuitbreaker.enabled=true") + .withPropertyValues("spring.cloud.polaris.circuitbreaker.configuration-cleanup-interval=5000"); private static MockedStatic mockedApplicationContextAwareUtils; @@ -92,6 +99,18 @@ public void run() { throw new RuntimeException("boom"); }, t -> "fallback")).isEqualTo("fallback"); + Method getConfigurationsMethod = ReflectionUtils.findMethod(PolarisCircuitBreakerFactory.class, + "getConfigurations"); + Assertions.assertNotNull(getConfigurationsMethod); + ReflectionUtils.makeAccessible(getConfigurationsMethod); + Map values = (Map) ReflectionUtils.invokeMethod(getConfigurationsMethod, polarisCircuitBreakerFactory); + Assertions.assertNotNull(values); + + Assertions.assertEquals(1, values.size()); + + Utils.sleepUninterrupted(10 * 1000); + + Assertions.assertEquals(0, values.size()); }); } 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 index f06502c87..7507ae43c 100644 --- 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 @@ -17,15 +17,20 @@ package com.tencent.cloud.polaris.circuitbreaker; +import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collections; +import java.util.Map; import com.tencent.cloud.common.util.ApplicationContextAwareUtils; +import com.tencent.cloud.common.util.ReflectionUtils; 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 com.tencent.polaris.client.util.Utils; import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -58,7 +63,8 @@ public class ReactivePolarisCircuitBreakerTest { RpcEnhancementAutoConfiguration.class, LoadBalancerAutoConfiguration.class, ReactivePolarisCircuitBreakerAutoConfiguration.class)) - .withPropertyValues("spring.cloud.polaris.circuitbreaker.enabled=true"); + .withPropertyValues("spring.cloud.polaris.circuitbreaker.enabled=true") + .withPropertyValues("spring.cloud.polaris.circuitbreaker.configuration-cleanup-interval=5000"); private static MockedStatic mockedApplicationContextAwareUtils; @@ -97,6 +103,18 @@ public void run() { assertThat(Flux.error(new RuntimeException("boom")).transform(it -> cb.run(it, t -> Flux.just("fallback"))) .collectList().block()).isEqualTo(Collections.singletonList("fallback")); + + Method getConfigurationsMethod = ReflectionUtils.findMethod(PolarisCircuitBreakerFactory.class, + "getConfigurations"); + Assertions.assertNotNull(getConfigurationsMethod); + ReflectionUtils.makeAccessible(getConfigurationsMethod); + Map values = (Map) ReflectionUtils.invokeMethod(getConfigurationsMethod, polarisCircuitBreakerFactory); + Assertions.assertNotNull(values); + Assertions.assertEquals(1, values.size()); + + Utils.sleepUninterrupted(10 * 1000); + + Assertions.assertEquals(0, values.size()); }); } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationTest.java index b4d46a476..25337f709 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationTest.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationTest.java @@ -31,6 +31,7 @@ import com.google.protobuf.util.JsonFormat; import com.tencent.cloud.polaris.circuitbreaker.PolarisCircuitBreakerFactory; import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerFeignClientAutoConfiguration; +import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerProperties; import com.tencent.cloud.polaris.circuitbreaker.reporter.ExceptionCircuitBreakerReporter; import com.tencent.cloud.polaris.circuitbreaker.reporter.SuccessCircuitBreakerReporter; import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties; @@ -232,8 +233,9 @@ public ExceptionCircuitBreakerReporter exceptionCircuitBreakerReporter(RpcEnhanc @Bean @ConditionalOnMissingBean(CircuitBreakerFactory.class) - public CircuitBreakerFactory polarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, ConsumerAPI consumerAPI) { - PolarisCircuitBreakerFactory factory = new PolarisCircuitBreakerFactory(circuitBreakAPI, consumerAPI); + public CircuitBreakerFactory polarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, + ConsumerAPI consumerAPI, PolarisCircuitBreakerProperties polarisCircuitBreakerProperties) { + PolarisCircuitBreakerFactory factory = new PolarisCircuitBreakerFactory(circuitBreakAPI, consumerAPI, polarisCircuitBreakerProperties); customizers.forEach(customizer -> customizer.customize(factory)); return factory; } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/gateway/PolarisCircuitBreakerGatewayIntegrationTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/gateway/PolarisCircuitBreakerGatewayIntegrationTest.java index 2aec7cc5a..ad041d022 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/gateway/PolarisCircuitBreakerGatewayIntegrationTest.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/gateway/PolarisCircuitBreakerGatewayIntegrationTest.java @@ -32,6 +32,7 @@ import com.google.protobuf.util.JsonFormat; import com.tencent.cloud.polaris.circuitbreaker.PolarisCircuitBreakerFactory; +import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerProperties; import com.tencent.cloud.polaris.circuitbreaker.reporter.ExceptionCircuitBreakerReporter; import com.tencent.cloud.polaris.circuitbreaker.reporter.SuccessCircuitBreakerReporter; import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties; @@ -218,8 +219,9 @@ public ExceptionCircuitBreakerReporter exceptionCircuitBreakerReporter(RpcEnhanc @Bean @ConditionalOnMissingBean(CircuitBreakerFactory.class) - public CircuitBreakerFactory polarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, ConsumerAPI consumerAPI) { - PolarisCircuitBreakerFactory factory = new PolarisCircuitBreakerFactory(circuitBreakAPI, consumerAPI); + public CircuitBreakerFactory polarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, ConsumerAPI consumerAPI, + PolarisCircuitBreakerProperties polarisCircuitBreakerProperties) { + PolarisCircuitBreakerFactory factory = new PolarisCircuitBreakerFactory(circuitBreakAPI, consumerAPI, polarisCircuitBreakerProperties); customizers.forEach(customizer -> customizer.customize(factory)); return factory; } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisCircuitBreakerRestTemplateIntegrationTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisCircuitBreakerRestTemplateIntegrationTest.java index 2080b63c8..14e41ae8b 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisCircuitBreakerRestTemplateIntegrationTest.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisCircuitBreakerRestTemplateIntegrationTest.java @@ -32,6 +32,7 @@ import com.google.protobuf.util.JsonFormat; import com.tencent.cloud.polaris.circuitbreaker.PolarisCircuitBreakerFactory; import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerFeignClientAutoConfiguration; +import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerProperties; import com.tencent.cloud.polaris.circuitbreaker.reporter.ExceptionCircuitBreakerReporter; import com.tencent.cloud.polaris.circuitbreaker.reporter.SuccessCircuitBreakerReporter; import com.tencent.cloud.polaris.context.PolarisSDKContextManager; @@ -291,9 +292,9 @@ public ExceptionCircuitBreakerReporter exceptionCircuitBreakerReporter(RpcEnhanc @Bean @ConditionalOnMissingBean(CircuitBreakerFactory.class) public CircuitBreakerFactory polarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, - PolarisSDKContextManager polarisSDKContextManager) { + PolarisSDKContextManager polarisSDKContextManager, PolarisCircuitBreakerProperties polarisCircuitBreakerProperties) { PolarisCircuitBreakerFactory factory = new PolarisCircuitBreakerFactory( - circuitBreakAPI, polarisSDKContextManager.getConsumerAPI()); + circuitBreakAPI, polarisSDKContextManager.getConsumerAPI(), polarisCircuitBreakerProperties); customizers.forEach(customizer -> customizer.customize(factory)); return factory; } diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerController.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerController.java index 5b348144b..1dbd829a3 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerController.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerController.java @@ -116,6 +116,26 @@ public String circuitBreakRestTemplate() { ); } + /** + * RestTemplate wildcard circuit breaker with fallback from Polaris. + * @return circuit breaker information of callee + */ + @GetMapping("/rest/fallbackFromPolaris/wildcard/{uid}") + public ResponseEntity circuitBreakRestTemplateFallbackFromPolarisWildcard(@PathVariable String uid) { + String path = String.format("/quickstart/callee/circuitBreak/wildcard/%s", uid); + return restTemplateFallbackFromPolaris.getForEntity(path, String.class); + } + + /** + * RestTemplate wildcard circuit breaker with fallback from code. + * @return circuit breaker information of callee + */ + @GetMapping("/rest/fallbackFromCode/wildcard/{uid}") + public ResponseEntity circuitBreakRestTemplateFallbackFromCodeWildcard(@PathVariable String uid) { + String path = String.format("/quickstart/callee/circuitBreak/wildcard/%s", uid); + return restTemplateFallbackFromCode.getForEntity(path, String.class); + } + /** * RestTemplate circuit breaker with fallback from Polaris. * @return circuit breaker information of callee diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/src/main/resources/application.yml b/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/src/main/resources/application.yml index fd9dd9f05..d47b3fd87 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/src/main/resources/application.yml +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/src/main/resources/application.yml @@ -20,6 +20,8 @@ spring: address: grpc://119.91.66.223:8091 namespace: default enabled: true + circuitbreaker: + enabled: true contract: exposure: true report: