Skip to content

Commit 3f6ed5c

Browse files
authored
fix: fix PolarisCircuitBreakerConfiguration not clear when gateway invoke by wildcard apis (#1418)
1 parent ef48295 commit 3f6ed5c

File tree

16 files changed

+205
-23
lines changed

16 files changed

+205
-23
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,5 @@
3030
- [feat:support TSF router.](https://github.com/Tencent/spring-cloud-tencent/pull/1368)
3131
- [feat:upgrade nearby router and add namespace nearby router.](https://github.com/Tencent/spring-cloud-tencent/pull/1371)
3232
- [fix:fix contract reporting bug when using TSF.](https://github.com/Tencent/spring-cloud-tencent/pull/1373)
33-
- [fix: fix TSF context bootstrap configuration](https://github.com/Tencent/spring-cloud-tencent/pull/1395)
33+
- [fix: fix TSF context bootstrap configuration](https://github.com/Tencent/spring-cloud-tencent/pull/1395)
34+
- [fix: fix PolarisCircuitBreakerConfiguration not clear when gateway invoke by wildcard apis](https://github.com/Tencent/spring-cloud-tencent/pull/1418)

spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerFactory.java

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,21 @@
1717

1818
package com.tencent.cloud.polaris.circuitbreaker;
1919

20+
import java.util.concurrent.ExecutorService;
21+
import java.util.concurrent.Executors;
22+
import java.util.concurrent.ScheduledExecutorService;
23+
import java.util.concurrent.TimeUnit;
2024
import java.util.function.Function;
2125

2226
import com.tencent.cloud.polaris.circuitbreaker.common.PolarisCircuitBreakerConfigBuilder;
27+
import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerProperties;
2328
import com.tencent.cloud.polaris.circuitbreaker.util.PolarisCircuitBreakerUtils;
2429
import com.tencent.polaris.api.core.ConsumerAPI;
30+
import com.tencent.polaris.api.utils.ThreadPoolUtils;
2531
import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI;
32+
import com.tencent.polaris.client.util.NamedThreadFactory;
2633

34+
import org.springframework.beans.factory.DisposableBean;
2735
import org.springframework.cloud.client.circuitbreaker.CircuitBreaker;
2836
import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory;
2937

@@ -33,7 +41,7 @@
3341
* @author seanyu 2023-02-27
3442
*/
3543
public class PolarisCircuitBreakerFactory
36-
extends CircuitBreakerFactory<PolarisCircuitBreakerConfigBuilder.PolarisCircuitBreakerConfiguration, PolarisCircuitBreakerConfigBuilder> {
44+
extends CircuitBreakerFactory<PolarisCircuitBreakerConfigBuilder.PolarisCircuitBreakerConfiguration, PolarisCircuitBreakerConfigBuilder> implements DisposableBean {
3745

3846
private Function<String, PolarisCircuitBreakerConfigBuilder.PolarisCircuitBreakerConfiguration> defaultConfiguration =
3947
id -> {
@@ -50,9 +58,19 @@ public class PolarisCircuitBreakerFactory
5058

5159
private final ConsumerAPI consumerAPI;
5260

53-
public PolarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, ConsumerAPI consumerAPI) {
61+
private final ScheduledExecutorService cleanupService = Executors.newSingleThreadScheduledExecutor(
62+
new NamedThreadFactory("sct-circuitbreaker-cleanup", true));
63+
64+
public PolarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, ConsumerAPI consumerAPI,
65+
PolarisCircuitBreakerProperties polarisCircuitBreakerProperties) {
5466
this.circuitBreakAPI = circuitBreakAPI;
5567
this.consumerAPI = consumerAPI;
68+
cleanupService.scheduleWithFixedDelay(
69+
() -> {
70+
getConfigurations().clear();
71+
},
72+
polarisCircuitBreakerProperties.getConfigurationCleanupInterval(),
73+
polarisCircuitBreakerProperties.getConfigurationCleanupInterval(), TimeUnit.MILLISECONDS);
5674
}
5775

5876
@Override
@@ -73,4 +91,9 @@ public void configureDefault(Function<String, PolarisCircuitBreakerConfigBuilder
7391
this.defaultConfiguration = defaultConfiguration;
7492
}
7593

94+
@Override
95+
public void destroy() {
96+
ThreadPoolUtils.waitAndStopThreadPools(new ExecutorService[]{cleanupService});
97+
}
98+
7699
}

spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/ReactivePolarisCircuitBreakerFactory.java

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,21 @@
1717

1818
package com.tencent.cloud.polaris.circuitbreaker;
1919

20+
import java.util.concurrent.ExecutorService;
21+
import java.util.concurrent.Executors;
22+
import java.util.concurrent.ScheduledExecutorService;
23+
import java.util.concurrent.TimeUnit;
2024
import java.util.function.Function;
2125

2226
import com.tencent.cloud.polaris.circuitbreaker.common.PolarisCircuitBreakerConfigBuilder;
27+
import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerProperties;
2328
import com.tencent.cloud.polaris.circuitbreaker.util.PolarisCircuitBreakerUtils;
2429
import com.tencent.polaris.api.core.ConsumerAPI;
30+
import com.tencent.polaris.api.utils.ThreadPoolUtils;
2531
import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI;
32+
import com.tencent.polaris.client.util.NamedThreadFactory;
2633

34+
import org.springframework.beans.factory.DisposableBean;
2735
import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreaker;
2836
import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreakerFactory;
2937

@@ -33,7 +41,7 @@
3341
* @author seanyu 2023-02-27
3442
*/
3543
public class ReactivePolarisCircuitBreakerFactory extends
36-
ReactiveCircuitBreakerFactory<PolarisCircuitBreakerConfigBuilder.PolarisCircuitBreakerConfiguration, PolarisCircuitBreakerConfigBuilder> {
44+
ReactiveCircuitBreakerFactory<PolarisCircuitBreakerConfigBuilder.PolarisCircuitBreakerConfiguration, PolarisCircuitBreakerConfigBuilder> implements DisposableBean {
3745

3846
private Function<String, PolarisCircuitBreakerConfigBuilder.PolarisCircuitBreakerConfiguration> defaultConfiguration =
3947
id -> {
@@ -49,9 +57,19 @@ public class ReactivePolarisCircuitBreakerFactory extends
4957

5058
private final ConsumerAPI consumerAPI;
5159

52-
public ReactivePolarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, ConsumerAPI consumerAPI) {
60+
private final ScheduledExecutorService cleanupService = Executors.newSingleThreadScheduledExecutor(
61+
new NamedThreadFactory("sct-reactive-circuitbreaker-cleanup", true));
62+
63+
public ReactivePolarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, ConsumerAPI consumerAPI,
64+
PolarisCircuitBreakerProperties polarisCircuitBreakerProperties) {
5365
this.circuitBreakAPI = circuitBreakAPI;
5466
this.consumerAPI = consumerAPI;
67+
cleanupService.scheduleWithFixedDelay(
68+
() -> {
69+
getConfigurations().clear();
70+
},
71+
polarisCircuitBreakerProperties.getConfigurationCleanupInterval(),
72+
polarisCircuitBreakerProperties.getConfigurationCleanupInterval(), TimeUnit.MILLISECONDS);
5573
}
5674

5775

@@ -73,4 +91,8 @@ public void configureDefault(
7391
this.defaultConfiguration = defaultConfiguration;
7492
}
7593

94+
@Override
95+
public void destroy() {
96+
ThreadPoolUtils.waitAndStopThreadPools(new ExecutorService[]{cleanupService});
97+
}
7698
}

spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerAutoConfiguration.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
3434
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
3535
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
36+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
3637
import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory;
3738
import org.springframework.cloud.client.circuitbreaker.Customizer;
3839
import org.springframework.context.ApplicationContext;
@@ -47,6 +48,7 @@
4748
*/
4849
@Configuration(proxyBeanMethods = false)
4950
@ConditionalOnPolarisCircuitBreakerEnabled
51+
@EnableConfigurationProperties(PolarisCircuitBreakerProperties.class)
5052
@AutoConfigureAfter(RpcEnhancementAutoConfiguration.class)
5153
public class PolarisCircuitBreakerAutoConfiguration {
5254

@@ -76,9 +78,10 @@ public ExceptionCircuitBreakerReporter exceptionCircuitBreakerReporter(RpcEnhanc
7678

7779
@Bean
7880
@ConditionalOnMissingBean(CircuitBreakerFactory.class)
79-
public CircuitBreakerFactory polarisCircuitBreakerFactory(PolarisSDKContextManager polarisSDKContextManager) {
81+
public CircuitBreakerFactory polarisCircuitBreakerFactory(PolarisSDKContextManager polarisSDKContextManager,
82+
PolarisCircuitBreakerProperties polarisCircuitBreakerProperties) {
8083
PolarisCircuitBreakerFactory factory = new PolarisCircuitBreakerFactory(
81-
polarisSDKContextManager.getCircuitBreakAPI(), polarisSDKContextManager.getConsumerAPI());
84+
polarisSDKContextManager.getCircuitBreakAPI(), polarisSDKContextManager.getConsumerAPI(), polarisCircuitBreakerProperties);
8285
customizers.forEach(customizer -> customizer.customize(factory));
8386
return factory;
8487
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
3+
*
4+
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
5+
*
6+
* Licensed under the BSD 3-Clause License (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* https://opensource.org/licenses/BSD-3-Clause
11+
*
12+
* Unless required by applicable law or agreed to in writing, software distributed
13+
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
14+
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
15+
* specific language governing permissions and limitations under the License.
16+
*/
17+
18+
package com.tencent.cloud.polaris.circuitbreaker.config;
19+
20+
import org.springframework.beans.factory.annotation.Value;
21+
import org.springframework.boot.context.properties.ConfigurationProperties;
22+
23+
/**
24+
* Properties of Polaris CircuitBreaker .
25+
*
26+
*/
27+
@ConfigurationProperties("spring.cloud.polaris.circuitbreaker")
28+
public class PolarisCircuitBreakerProperties {
29+
30+
/**
31+
* Whether enable polaris circuit-breaker function.
32+
*/
33+
@Value("${spring.cloud.polaris.circuitbreaker.enabled:#{true}}")
34+
private boolean enabled = true;
35+
36+
/**
37+
* Interval to clean up PolarisCircuitBreakerConfiguration, unit millisecond.
38+
*/
39+
@Value("${spring.cloud.polaris.circuitbreaker.configuration-cleanup-interval:#{300000}}")
40+
private long configurationCleanupInterval = 300000;
41+
42+
public boolean isEnabled() {
43+
return enabled;
44+
}
45+
46+
public void setEnabled(boolean enabled) {
47+
this.enabled = enabled;
48+
}
49+
50+
public long getConfigurationCleanupInterval() {
51+
return configurationCleanupInterval;
52+
}
53+
54+
public void setConfigurationCleanupInterval(long configurationCleanupInterval) {
55+
this.configurationCleanupInterval = configurationCleanupInterval;
56+
}
57+
}

spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/ReactivePolarisCircuitBreakerAutoConfiguration.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
3333
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
3434
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
35+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
3536
import org.springframework.cloud.client.circuitbreaker.Customizer;
3637
import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreakerFactory;
3738
import org.springframework.context.annotation.Bean;
@@ -45,6 +46,7 @@
4546
@Configuration(proxyBeanMethods = false)
4647
@ConditionalOnClass(name = {"reactor.core.publisher.Mono", "reactor.core.publisher.Flux"})
4748
@ConditionalOnPolarisCircuitBreakerEnabled
49+
@EnableConfigurationProperties(PolarisCircuitBreakerProperties.class)
4850
@AutoConfigureAfter(RpcEnhancementAutoConfiguration.class)
4951
public class ReactivePolarisCircuitBreakerAutoConfiguration {
5052

@@ -67,9 +69,10 @@ public ExceptionCircuitBreakerReporter exceptionCircuitBreakerReporter(RpcEnhanc
6769

6870
@Bean
6971
@ConditionalOnMissingBean(ReactiveCircuitBreakerFactory.class)
70-
public ReactiveCircuitBreakerFactory polarisReactiveCircuitBreakerFactory(PolarisSDKContextManager polarisSDKContextManager) {
72+
public ReactiveCircuitBreakerFactory polarisReactiveCircuitBreakerFactory(PolarisSDKContextManager polarisSDKContextManager,
73+
PolarisCircuitBreakerProperties polarisCircuitBreakerProperties) {
7174
ReactivePolarisCircuitBreakerFactory factory = new ReactivePolarisCircuitBreakerFactory(
72-
polarisSDKContextManager.getCircuitBreakAPI(), polarisSDKContextManager.getConsumerAPI());
75+
polarisSDKContextManager.getCircuitBreakAPI(), polarisSDKContextManager.getConsumerAPI(), polarisCircuitBreakerProperties);
7376
customizers.forEach(customizer -> customizer.customize(factory));
7477
return factory;
7578
}

spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/util/PolarisCircuitBreakerUtils.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,12 @@ public static String[] resolveCircuitBreakerId(String id) {
5555
Assert.hasText(id, "A CircuitBreaker must have an id. Id could be : namespace#service#method or service#method or service");
5656
String[] polarisCircuitBreakerMetaData = id.split("#");
5757
if (polarisCircuitBreakerMetaData.length == 2) {
58-
return new String[]{MetadataContext.LOCAL_NAMESPACE, polarisCircuitBreakerMetaData[0], polarisCircuitBreakerMetaData[1]};
58+
return new String[] {MetadataContext.LOCAL_NAMESPACE, polarisCircuitBreakerMetaData[0], polarisCircuitBreakerMetaData[1]};
5959
}
6060
if (polarisCircuitBreakerMetaData.length == 3) {
61-
return new String[]{polarisCircuitBreakerMetaData[0], polarisCircuitBreakerMetaData[1], polarisCircuitBreakerMetaData[2]};
61+
return new String[] {polarisCircuitBreakerMetaData[0], polarisCircuitBreakerMetaData[1], polarisCircuitBreakerMetaData[2]};
6262
}
63-
return new String[]{MetadataContext.LOCAL_NAMESPACE, id, ""};
63+
return new String[] {MetadataContext.LOCAL_NAMESPACE, id, ""};
6464
}
6565

6666
public static void reportStatus(ConsumerAPI consumerAPI,

spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/resources/META-INF/additional-spring-configuration-metadata.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,14 @@
33
{
44
"name": "spring.cloud.polaris.circuitbreaker.enabled",
55
"type": "java.lang.Boolean",
6-
"defaultValue": "true"
6+
"defaultValue": "true",
7+
"description": "If polaris circuitbreaker enabled."
8+
},
9+
{
10+
"name": "spring.cloud.polaris.circuitbreaker.configuration-cleanup-interval",
11+
"type": "java.lang.Long",
12+
"defaultValue": "300000",
13+
"description": "Interval to clean up PolarisCircuitBreakerConfiguration, unit millisecond."
714
}
815
],
916
"hints": []

spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerMockServerTest.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
import com.google.protobuf.util.JsonFormat;
3232
import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
33+
import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerProperties;
3334
import com.tencent.cloud.polaris.context.PolarisSDKContextManager;
3435
import com.tencent.polaris.api.config.Configuration;
3536
import com.tencent.polaris.api.core.ConsumerAPI;
@@ -108,7 +109,8 @@ public void testCircuitBreaker() {
108109
CircuitBreakAPI circuitBreakAPI = CircuitBreakAPIFactory.createCircuitBreakAPIByConfig(configuration);
109110

110111
ConsumerAPI consumerAPI = DiscoveryAPIFactory.createConsumerAPIByConfig(configuration);
111-
PolarisCircuitBreakerFactory polarisCircuitBreakerFactory = new PolarisCircuitBreakerFactory(circuitBreakAPI, consumerAPI);
112+
PolarisCircuitBreakerProperties polarisCircuitBreakerProperties = new PolarisCircuitBreakerProperties();
113+
PolarisCircuitBreakerFactory polarisCircuitBreakerFactory = new PolarisCircuitBreakerFactory(circuitBreakAPI, consumerAPI, polarisCircuitBreakerProperties);
112114
CircuitBreaker cb = polarisCircuitBreakerFactory.create(SERVICE_CIRCUIT_BREAKER);
113115

114116
// trigger fallback for 5 times
@@ -129,7 +131,7 @@ public void testCircuitBreaker() {
129131
assertThat(resList).isEqualTo(Arrays.asList("invoke success", "fallback", "fallback", "fallback", "fallback"));
130132

131133
// always fallback
132-
ReactivePolarisCircuitBreakerFactory reactivePolarisCircuitBreakerFactory = new ReactivePolarisCircuitBreakerFactory(circuitBreakAPI, consumerAPI);
134+
ReactivePolarisCircuitBreakerFactory reactivePolarisCircuitBreakerFactory = new ReactivePolarisCircuitBreakerFactory(circuitBreakAPI, consumerAPI, polarisCircuitBreakerProperties);
133135
ReactiveCircuitBreaker rcb = reactivePolarisCircuitBreakerFactory.create(SERVICE_CIRCUIT_BREAKER);
134136

135137
assertThat(Mono.just("foobar").transform(it -> rcb.run(it, t -> Mono.just("fallback")))

spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerTest.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,19 @@
1818
package com.tencent.cloud.polaris.circuitbreaker;
1919

2020

21+
import java.lang.reflect.Method;
22+
import java.util.Map;
23+
2124
import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
25+
import com.tencent.cloud.common.util.ReflectionUtils;
2226
import com.tencent.cloud.polaris.circuitbreaker.common.PolarisCircuitBreakerConfigBuilder;
2327
import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerAutoConfiguration;
2428
import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerFeignClientAutoConfiguration;
2529
import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration;
2630
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementAutoConfiguration;
31+
import com.tencent.polaris.client.util.Utils;
2732
import org.junit.jupiter.api.AfterAll;
33+
import org.junit.jupiter.api.Assertions;
2834
import org.junit.jupiter.api.BeforeAll;
2935
import org.junit.jupiter.api.Test;
3036
import org.junit.jupiter.api.extension.ExtendWith;
@@ -56,7 +62,8 @@ public class PolarisCircuitBreakerTest {
5662
LoadBalancerAutoConfiguration.class,
5763
PolarisCircuitBreakerFeignClientAutoConfiguration.class,
5864
PolarisCircuitBreakerAutoConfiguration.class))
59-
.withPropertyValues("spring.cloud.polaris.circuitbreaker.enabled=true");
65+
.withPropertyValues("spring.cloud.polaris.circuitbreaker.enabled=true")
66+
.withPropertyValues("spring.cloud.polaris.circuitbreaker.configuration-cleanup-interval=5000");
6067

6168
private static MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils;
6269

@@ -92,6 +99,18 @@ public void run() {
9299
throw new RuntimeException("boom");
93100
}, t -> "fallback")).isEqualTo("fallback");
94101

102+
Method getConfigurationsMethod = ReflectionUtils.findMethod(PolarisCircuitBreakerFactory.class,
103+
"getConfigurations");
104+
Assertions.assertNotNull(getConfigurationsMethod);
105+
ReflectionUtils.makeAccessible(getConfigurationsMethod);
106+
Map<?, ?> values = (Map<?, ?>) ReflectionUtils.invokeMethod(getConfigurationsMethod, polarisCircuitBreakerFactory);
107+
Assertions.assertNotNull(values);
108+
109+
Assertions.assertEquals(1, values.size());
110+
111+
Utils.sleepUninterrupted(10 * 1000);
112+
113+
Assertions.assertEquals(0, values.size());
95114
});
96115
}
97116

0 commit comments

Comments
 (0)