feat:support concurrency rate limit. (#1456)

* feat:support concurrency rate limit.

* feat:support concurrency rate limit.
pull/1460/head
Haotian Zhang 3 weeks ago committed by GitHub
parent 0ff874ff76
commit e89bdae432
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -15,7 +15,7 @@
- [fix: fix lossless deregister failed when no healthcheck configured](https://github.com/Tencent/spring-cloud-tencent/pull/1345)
- [feat:add zero protection.](https://github.com/Tencent/spring-cloud-tencent/pull/1346)
- [fix:fix no registry when lossless is disabled.](https://github.com/Tencent/spring-cloud-tencent/pull/1347)
- [fix:fix the ratelimit bug for 2022](https://github.com/Tencent/spring-cloud-tencent/pull/1348)
- [fix:fix the ratelimit bug for 2021](https://github.com/Tencent/spring-cloud-tencent/pull/1348)
- [feat:add Tencent Cloud TSF support.](https://github.com/Tencent/spring-cloud-tencent/pull/1350)
- [feat:support consul config.](https://github.com/Tencent/spring-cloud-tencent/pull/1352)
- [feat:add trace report support.](https://github.com/Tencent/spring-cloud-tencent/pull/1353)
@ -35,3 +35,4 @@
- [feat:upgrade api circuit breaker.](https://github.com/Tencent/spring-cloud-tencent/pull/1440)
- [feat: support lossless config from console & support warmup.](https://github.com/Tencent/spring-cloud-tencent/pull/1446)
- [feat:add admin http handler.](https://github.com/Tencent/spring-cloud-tencent/pull/1449)
- [feat:support concurrency rate limit.](https://github.com/Tencent/spring-cloud-tencent/pull/1456)

@ -25,7 +25,6 @@ import com.tencent.cloud.metadata.core.EncodeTransferMedataFeignEnhancedPlugin;
import com.tencent.cloud.metadata.core.EncodeTransferMedataRestTemplateEnhancedPlugin;
import com.tencent.cloud.metadata.core.EncodeTransferMedataScgEnhancedPlugin;
import com.tencent.cloud.metadata.core.EncodeTransferMedataWebClientEnhancedPlugin;
import com.tencent.cloud.polaris.context.config.PolarisContextProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@ -66,8 +65,8 @@ public class MetadataTransferAutoConfiguration {
}
@Bean
public DecodeTransferMetadataServletFilter metadataServletFilter(PolarisContextProperties polarisContextProperties) {
return new DecodeTransferMetadataServletFilter(polarisContextProperties);
public DecodeTransferMetadataServletFilter metadataServletFilter() {
return new DecodeTransferMetadataServletFilter();
}
}
@ -79,8 +78,8 @@ public class MetadataTransferAutoConfiguration {
protected static class MetadataReactiveFilterConfig {
@Bean
public DecodeTransferMetadataReactiveFilter metadataReactiveFilter(PolarisContextProperties polarisContextProperties) {
return new DecodeTransferMetadataReactiveFilter(polarisContextProperties);
public DecodeTransferMetadataReactiveFilter metadataReactiveFilter() {
return new DecodeTransferMetadataReactiveFilter();
}
}

@ -27,7 +27,6 @@ import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.common.util.JacksonUtils;
import com.tencent.cloud.common.util.UrlUtils;
import com.tencent.cloud.metadata.provider.ReactiveMetadataProvider;
import com.tencent.cloud.polaris.context.config.PolarisContextProperties;
import com.tencent.polaris.api.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -54,11 +53,6 @@ import static com.tencent.polaris.metadata.core.constant.MetadataConstants.LOCAL
public class DecodeTransferMetadataReactiveFilter implements WebFilter, Ordered {
private static final Logger LOG = LoggerFactory.getLogger(DecodeTransferMetadataReactiveFilter.class);
private PolarisContextProperties polarisContextProperties;
public DecodeTransferMetadataReactiveFilter(PolarisContextProperties polarisContextProperties) {
this.polarisContextProperties = polarisContextProperties;
}
@Override
public int getOrder() {

@ -32,7 +32,6 @@ import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.common.util.JacksonUtils;
import com.tencent.cloud.common.util.UrlUtils;
import com.tencent.cloud.metadata.provider.ServletMetadataProvider;
import com.tencent.cloud.polaris.context.config.PolarisContextProperties;
import com.tencent.polaris.api.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -57,12 +56,6 @@ public class DecodeTransferMetadataServletFilter extends OncePerRequestFilter {
private static final Logger LOG = LoggerFactory.getLogger(DecodeTransferMetadataServletFilter.class);
private PolarisContextProperties polarisContextProperties;
public DecodeTransferMetadataServletFilter(PolarisContextProperties polarisContextProperties) {
this.polarisContextProperties = polarisContextProperties;
}
@Override
protected void doFilterInternal(@NonNull HttpServletRequest httpServletRequest,
@NonNull HttpServletResponse httpServletResponse, FilterChain filterChain)

@ -20,7 +20,6 @@ package com.tencent.cloud.metadata.core;
import com.tencent.cloud.common.constant.MetadataConstant;
import com.tencent.cloud.common.constant.OrderConstant;
import com.tencent.cloud.common.metadata.config.MetadataLocalProperties;
import com.tencent.cloud.polaris.context.config.PolarisContextProperties;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@ -55,7 +54,7 @@ public class DecodeTransferMetadataReactiveFilterTest {
@BeforeEach
public void setUp() {
this.metadataReactiveFilter = new DecodeTransferMetadataReactiveFilter(new PolarisContextProperties());
this.metadataReactiveFilter = new DecodeTransferMetadataReactiveFilter();
}
@Test

@ -1,73 +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.ratelimit;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.tencent.cloud.common.util.expresstion.ExpressionLabelUtils;
import com.tencent.cloud.polaris.context.ServiceRuleManager;
import com.tencent.polaris.specification.api.v1.model.ModelProto;
import com.tencent.polaris.specification.api.v1.traffic.manage.RateLimitProto;
import org.springframework.util.CollectionUtils;
/**
* resolve labels from rate limit rule.
*
*@author lepdou 2022-05-13
*/
@Deprecated
public class RateLimitRuleLabelResolver {
private final ServiceRuleManager serviceRuleManager;
public RateLimitRuleLabelResolver(ServiceRuleManager serviceRuleManager) {
this.serviceRuleManager = serviceRuleManager;
}
public Set<String> getExpressionLabelKeys(String namespace, String service) {
RateLimitProto.RateLimit rateLimitRule = serviceRuleManager.getServiceRateLimitRule(namespace, service);
if (rateLimitRule == null) {
return Collections.emptySet();
}
List<RateLimitProto.Rule> rules = rateLimitRule.getRulesList();
if (CollectionUtils.isEmpty(rules)) {
return Collections.emptySet();
}
Set<String> expressionLabels = new HashSet<>();
for (RateLimitProto.Rule rule : rules) {
Map<String, ModelProto.MatchString> labels = rule.getLabelsMap();
if (CollectionUtils.isEmpty(labels)) {
return Collections.emptySet();
}
for (String key : labels.keySet()) {
if (ExpressionLabelUtils.isExpressionLabel(key)) {
expressionLabels.add(key);
}
}
}
return expressionLabels;
}
}

@ -20,14 +20,9 @@ package com.tencent.cloud.polaris.ratelimit.config;
import com.tencent.cloud.common.constant.OrderConstant;
import com.tencent.cloud.polaris.context.PolarisSDKContextManager;
import com.tencent.cloud.polaris.context.ServiceRuleManager;
import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration;
import com.tencent.cloud.polaris.ratelimit.filter.QuotaCheckReactiveFilter;
import com.tencent.cloud.polaris.ratelimit.filter.QuotaCheckServletFilter;
import com.tencent.cloud.polaris.ratelimit.resolver.RateLimitRuleArgumentReactiveResolver;
import com.tencent.cloud.polaris.ratelimit.resolver.RateLimitRuleArgumentServletResolver;
import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelReactiveResolver;
import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelServletResolver;
import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLimitedFallback;
import org.springframework.beans.factory.annotation.Autowired;
@ -63,20 +58,13 @@ public class PolarisRateLimitAutoConfiguration {
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
protected static class QuotaCheckFilterConfig {
@Bean
public RateLimitRuleArgumentServletResolver rateLimitRuleArgumentResolver(ServiceRuleManager serviceRuleManager,
@Autowired(required = false) PolarisRateLimiterLabelServletResolver labelResolver) {
return new RateLimitRuleArgumentServletResolver(serviceRuleManager, labelResolver);
}
@Bean
@ConditionalOnMissingBean
public QuotaCheckServletFilter quotaCheckFilter(PolarisSDKContextManager polarisSDKContextManager,
PolarisRateLimitProperties polarisRateLimitProperties,
RateLimitRuleArgumentServletResolver rateLimitRuleArgumentResolver,
@Autowired(required = false) PolarisRateLimiterLimitedFallback polarisRateLimiterLimitedFallback) {
return new QuotaCheckServletFilter(polarisSDKContextManager.getLimitAPI(), polarisRateLimitProperties,
rateLimitRuleArgumentResolver, polarisRateLimiterLimitedFallback);
return new QuotaCheckServletFilter(polarisSDKContextManager.getLimitAPI(), polarisSDKContextManager.getAssemblyAPI(),
polarisRateLimitProperties, polarisRateLimiterLimitedFallback);
}
@Bean
@ -97,21 +85,14 @@ public class PolarisRateLimitAutoConfiguration {
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
protected static class MetadataReactiveFilterConfig {
@Bean
public RateLimitRuleArgumentReactiveResolver rateLimitRuleArgumentResolver(ServiceRuleManager serviceRuleManager,
@Autowired(required = false) PolarisRateLimiterLabelReactiveResolver labelResolver) {
return new RateLimitRuleArgumentReactiveResolver(serviceRuleManager, labelResolver);
}
protected static class QuotaCheckReactiveFilterConfig {
@Bean
public QuotaCheckReactiveFilter quotaCheckReactiveFilter(PolarisSDKContextManager polarisSDKContextManager,
PolarisRateLimitProperties polarisRateLimitProperties,
RateLimitRuleArgumentReactiveResolver rateLimitRuleArgumentResolver,
@Nullable PolarisRateLimiterLimitedFallback polarisRateLimiterLimitedFallback) {
return new QuotaCheckReactiveFilter(polarisSDKContextManager.getLimitAPI(), polarisRateLimitProperties,
rateLimitRuleArgumentResolver, polarisRateLimiterLimitedFallback);
return new QuotaCheckReactiveFilter(polarisSDKContextManager.getLimitAPI(), polarisSDKContextManager.getAssemblyAPI(),
polarisRateLimitProperties, polarisRateLimiterLimitedFallback);
}
}
}

@ -23,7 +23,6 @@ import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.Objects;
import java.util.Set;
import javax.annotation.PostConstruct;
@ -31,13 +30,13 @@ import com.tencent.cloud.common.constant.HeaderConstant;
import com.tencent.cloud.common.constant.OrderConstant;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitProperties;
import com.tencent.cloud.polaris.ratelimit.resolver.RateLimitRuleArgumentReactiveResolver;
import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLimitedFallback;
import com.tencent.cloud.polaris.ratelimit.utils.QuotaCheckUtils;
import com.tencent.cloud.polaris.ratelimit.utils.RateLimitUtils;
import com.tencent.polaris.api.pojo.RetStatus;
import com.tencent.polaris.api.utils.StringUtils;
import com.tencent.polaris.assembly.api.AssemblyAPI;
import com.tencent.polaris.ratelimit.api.core.LimitAPI;
import com.tencent.polaris.ratelimit.api.rpc.Argument;
import com.tencent.polaris.ratelimit.api.rpc.QuotaResponse;
import com.tencent.polaris.ratelimit.api.rpc.QuotaResultCode;
import org.slf4j.Logger;
@ -54,6 +53,7 @@ import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import static com.tencent.cloud.common.constant.ContextConstant.UTF_8;
import static org.springframework.core.io.buffer.DefaultDataBufferFactory.DEFAULT_INITIAL_CAPACITY;
/**
* Reactive filter to check quota.
@ -66,22 +66,20 @@ public class QuotaCheckReactiveFilter implements WebFilter, Ordered {
private final LimitAPI limitAPI;
private final PolarisRateLimitProperties polarisRateLimitProperties;
private final AssemblyAPI assemblyAPI;
private final RateLimitRuleArgumentReactiveResolver rateLimitRuleArgumentResolver;
private final PolarisRateLimitProperties polarisRateLimitProperties;
private final PolarisRateLimiterLimitedFallback polarisRateLimiterLimitedFallback;
private String rejectTips;
public QuotaCheckReactiveFilter(LimitAPI limitAPI,
public QuotaCheckReactiveFilter(LimitAPI limitAPI, AssemblyAPI assemblyAPI,
PolarisRateLimitProperties polarisRateLimitProperties,
RateLimitRuleArgumentReactiveResolver rateLimitRuleArgumentResolver,
@Nullable PolarisRateLimiterLimitedFallback polarisRateLimiterLimitedFallback) {
this.limitAPI = limitAPI;
this.assemblyAPI = assemblyAPI;
this.polarisRateLimitProperties = polarisRateLimitProperties;
this.rateLimitRuleArgumentResolver = rateLimitRuleArgumentResolver;
this.polarisRateLimiterLimitedFallback = polarisRateLimiterLimitedFallback;
}
@ -100,31 +98,41 @@ public class QuotaCheckReactiveFilter implements WebFilter, Ordered {
String localNamespace = MetadataContext.LOCAL_NAMESPACE;
String localService = MetadataContext.LOCAL_SERVICE;
Set<Argument> arguments = rateLimitRuleArgumentResolver.getArguments(exchange, localNamespace, localService);
long waitMs = -1;
QuotaResponse quotaResponse = null;
try {
String path = exchange.getRequest().getURI().getPath();
QuotaResponse quotaResponse = QuotaCheckUtils.getQuota(
limitAPI, localNamespace, localService, 1, arguments, path);
quotaResponse = QuotaCheckUtils.getQuota(limitAPI, localNamespace, localService, 1, path);
if (quotaResponse.getCode() == QuotaResultCode.QuotaResultLimited) {
ServerHttpResponse response = exchange.getResponse();
DataBuffer dataBuffer;
if (!Objects.isNull(polarisRateLimiterLimitedFallback)) {
if (Objects.nonNull(quotaResponse.getActiveRule())
&& StringUtils.isNotBlank(quotaResponse.getActiveRule().getCustomResponse().getBody())) {
response.setRawStatusCode(polarisRateLimitProperties.getRejectHttpCode());
response.getHeaders().setContentType(MediaType.TEXT_PLAIN);
dataBuffer = response.bufferFactory().allocateBuffer(DEFAULT_INITIAL_CAPACITY)
.write(quotaResponse.getActiveRule().getCustomResponse().getBody()
.getBytes(StandardCharsets.UTF_8));
}
else if (!Objects.isNull(polarisRateLimiterLimitedFallback)) {
response.setRawStatusCode(polarisRateLimiterLimitedFallback.rejectHttpCode());
response.getHeaders().setContentType(polarisRateLimiterLimitedFallback.mediaType());
dataBuffer = response.bufferFactory().allocateBuffer()
dataBuffer = response.bufferFactory().allocateBuffer(DEFAULT_INITIAL_CAPACITY)
.write(polarisRateLimiterLimitedFallback.rejectTips()
.getBytes(polarisRateLimiterLimitedFallback.charset()));
}
else {
response.setRawStatusCode(polarisRateLimitProperties.getRejectHttpCode());
response.getHeaders().setContentType(MediaType.TEXT_HTML);
dataBuffer = response.bufferFactory().allocateBuffer()
dataBuffer = response.bufferFactory().allocateBuffer(DEFAULT_INITIAL_CAPACITY)
.write(rejectTips.getBytes(StandardCharsets.UTF_8));
}
// set flow control to header
response.getHeaders()
.add(HeaderConstant.INTERNAL_CALLEE_RET_STATUS, RetStatus.RetFlowControl.getDesc());
// set trace span
RateLimitUtils.reportTrace(assemblyAPI, quotaResponse.getActiveRule().getId().getValue());
if (Objects.nonNull(quotaResponse.getActiveRule())) {
try {
String encodedActiveRuleName = URLEncoder.encode(
@ -136,6 +144,7 @@ public class QuotaCheckReactiveFilter implements WebFilter, Ordered {
quotaResponse.getActiveRuleName(), e);
}
}
RateLimitUtils.release(quotaResponse);
return response.writeWith(Mono.just(dataBuffer));
}
// Unirate
@ -150,11 +159,13 @@ public class QuotaCheckReactiveFilter implements WebFilter, Ordered {
LOG.error("fail to invoke getQuota, service is " + localService, t);
}
QuotaResponse finalQuotaResponse = quotaResponse;
if (waitMs > 0) {
return Mono.delay(Duration.ofMillis(waitMs)).flatMap(e -> chain.filter(exchange));
return Mono.delay(Duration.ofMillis(waitMs))
.flatMap(e -> chain.filter(exchange).doFinally((v) -> RateLimitUtils.release(finalQuotaResponse)));
}
else {
return chain.filter(exchange);
return chain.filter(exchange).doFinally((v) -> RateLimitUtils.release(finalQuotaResponse));
}
}

@ -22,7 +22,6 @@ import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Objects;
import java.util.Set;
import javax.annotation.PostConstruct;
import javax.servlet.FilterChain;
@ -34,13 +33,13 @@ import com.tencent.cloud.common.constant.HeaderConstant;
import com.tencent.cloud.common.constant.OrderConstant;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitProperties;
import com.tencent.cloud.polaris.ratelimit.resolver.RateLimitRuleArgumentServletResolver;
import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLimitedFallback;
import com.tencent.cloud.polaris.ratelimit.utils.QuotaCheckUtils;
import com.tencent.cloud.polaris.ratelimit.utils.RateLimitUtils;
import com.tencent.polaris.api.pojo.RetStatus;
import com.tencent.polaris.api.utils.StringUtils;
import com.tencent.polaris.assembly.api.AssemblyAPI;
import com.tencent.polaris.ratelimit.api.core.LimitAPI;
import com.tencent.polaris.ratelimit.api.rpc.Argument;
import com.tencent.polaris.ratelimit.api.rpc.QuotaResponse;
import com.tencent.polaris.ratelimit.api.rpc.QuotaResultCode;
import org.slf4j.Logger;
@ -69,21 +68,20 @@ public class QuotaCheckServletFilter extends OncePerRequestFilter {
private static final Logger LOG = LoggerFactory.getLogger(QuotaCheckServletFilter.class);
private final LimitAPI limitAPI;
private final PolarisRateLimitProperties polarisRateLimitProperties;
private final AssemblyAPI assemblyAPI;
private final RateLimitRuleArgumentServletResolver rateLimitRuleArgumentResolver;
private final PolarisRateLimitProperties polarisRateLimitProperties;
private final PolarisRateLimiterLimitedFallback polarisRateLimiterLimitedFallback;
private String rejectTips;
public QuotaCheckServletFilter(LimitAPI limitAPI,
public QuotaCheckServletFilter(LimitAPI limitAPI, AssemblyAPI assemblyAPI,
PolarisRateLimitProperties polarisRateLimitProperties,
RateLimitRuleArgumentServletResolver rateLimitRuleArgumentResolver,
@Nullable PolarisRateLimiterLimitedFallback polarisRateLimiterLimitedFallback) {
this.limitAPI = limitAPI;
this.assemblyAPI = assemblyAPI;
this.polarisRateLimitProperties = polarisRateLimitProperties;
this.rateLimitRuleArgumentResolver = rateLimitRuleArgumentResolver;
this.polarisRateLimiterLimitedFallback = polarisRateLimiterLimitedFallback;
}
@ -98,15 +96,17 @@ public class QuotaCheckServletFilter extends OncePerRequestFilter {
throws ServletException, IOException {
String localNamespace = MetadataContext.LOCAL_NAMESPACE;
String localService = MetadataContext.LOCAL_SERVICE;
Set<Argument> arguments = rateLimitRuleArgumentResolver.getArguments(request, localNamespace, localService);
QuotaResponse quotaResponse = null;
try {
QuotaResponse quotaResponse = QuotaCheckUtils.getQuota(limitAPI,
localNamespace, localService, 1, arguments, request.getRequestURI());
quotaResponse = QuotaCheckUtils.getQuota(limitAPI, localNamespace, localService, 1, request.getRequestURI());
if (quotaResponse.getCode() == QuotaResultCode.QuotaResultLimited) {
if (!Objects.isNull(polarisRateLimiterLimitedFallback)) {
if (Objects.nonNull(quotaResponse.getActiveRule())
&& StringUtils.isNotBlank(quotaResponse.getActiveRule().getCustomResponse().getBody())) {
response.setStatus(polarisRateLimitProperties.getRejectHttpCode());
response.setContentType("text/plain;charset=UTF-8");
response.getWriter().write(quotaResponse.getActiveRule().getCustomResponse().getBody());
}
else if (!Objects.isNull(polarisRateLimiterLimitedFallback)) {
response.setStatus(polarisRateLimiterLimitedFallback.rejectHttpCode());
String contentType = new MediaType(polarisRateLimiterLimitedFallback.mediaType(), polarisRateLimiterLimitedFallback.charset()).toString();
response.setContentType(contentType);
@ -117,7 +117,10 @@ public class QuotaCheckServletFilter extends OncePerRequestFilter {
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write(rejectTips);
}
// set flow control to header
response.addHeader(HeaderConstant.INTERNAL_CALLEE_RET_STATUS, RetStatus.RetFlowControl.getDesc());
// set trace span
RateLimitUtils.reportTrace(assemblyAPI, quotaResponse.getActiveRule().getId().getValue());
if (Objects.nonNull(quotaResponse.getActiveRule())) {
try {
String encodedActiveRuleName = URLEncoder.encode(
@ -129,6 +132,7 @@ public class QuotaCheckServletFilter extends OncePerRequestFilter {
quotaResponse.getActiveRuleName(), e);
}
}
RateLimitUtils.release(quotaResponse);
return;
}
// Unirate
@ -144,7 +148,12 @@ public class QuotaCheckServletFilter extends OncePerRequestFilter {
LOG.error("fail to invoke getQuota, service is " + localService, t);
}
filterChain.doFilter(request, response);
try {
filterChain.doFilter(request, response);
}
finally {
RateLimitUtils.release(quotaResponse);
}
}
}

@ -1,123 +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.ratelimit.resolver;
import java.net.InetSocketAddress;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.polaris.context.ServiceRuleManager;
import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelReactiveResolver;
import com.tencent.polaris.ratelimit.api.rpc.Argument;
import com.tencent.polaris.specification.api.v1.traffic.manage.RateLimitProto;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.web.server.ServerWebExchange;
import static com.tencent.cloud.common.constant.MetadataConstant.DefaultMetadata.DEFAULT_METADATA_SOURCE_SERVICE_NAME;
import static com.tencent.cloud.common.constant.MetadataConstant.DefaultMetadata.DEFAULT_METADATA_SOURCE_SERVICE_NAMESPACE;
/**
* resolve arguments from rate limit rule for Reactive.
*
* @author seansyyu 2023-03-09
*/
public class RateLimitRuleArgumentReactiveResolver {
private static final Logger LOG = LoggerFactory.getLogger(RateLimitRuleArgumentReactiveResolver.class);
private final ServiceRuleManager serviceRuleManager;
private final PolarisRateLimiterLabelReactiveResolver labelResolver;
public RateLimitRuleArgumentReactiveResolver(ServiceRuleManager serviceRuleManager, PolarisRateLimiterLabelReactiveResolver labelResolver) {
this.serviceRuleManager = serviceRuleManager;
this.labelResolver = labelResolver;
}
public Set<Argument> getArguments(ServerWebExchange request, String namespace, String service) {
RateLimitProto.RateLimit rateLimitRule = serviceRuleManager.getServiceRateLimitRule(namespace, service);
if (rateLimitRule == null) {
return Collections.emptySet();
}
List<RateLimitProto.Rule> rules = rateLimitRule.getRulesList();
if (CollectionUtils.isEmpty(rules)) {
return Collections.emptySet();
}
return rules.stream()
.flatMap(rule -> rule.getArgumentsList().stream())
.map(matchArgument -> {
String matchKey = matchArgument.getKey();
Argument argument = null;
switch (matchArgument.getType()) {
case CUSTOM:
argument = StringUtils.isBlank(matchKey) ? null :
Argument.buildCustom(matchKey, Optional.ofNullable(getCustomResolvedLabels(request).get(matchKey)).orElse(StringUtils.EMPTY));
break;
case METHOD:
argument = Argument.buildMethod(request.getRequest().getMethodValue());
break;
case HEADER:
argument = StringUtils.isBlank(matchKey) ? null :
Argument.buildHeader(matchKey, Optional.ofNullable(request.getRequest().getHeaders().getFirst(matchKey)).orElse(StringUtils.EMPTY));
break;
case QUERY:
argument = StringUtils.isBlank(matchKey) ? null :
Argument.buildQuery(matchKey, Optional.ofNullable(request.getRequest().getQueryParams().getFirst(matchKey)).orElse(StringUtils.EMPTY));
break;
case CALLER_SERVICE:
String sourceServiceNamespace = MetadataContextHolder.getDisposableMetadata(DEFAULT_METADATA_SOURCE_SERVICE_NAMESPACE, true).orElse(StringUtils.EMPTY);
String sourceServiceName = MetadataContextHolder.getDisposableMetadata(DEFAULT_METADATA_SOURCE_SERVICE_NAME, true).orElse(StringUtils.EMPTY);
if (!StringUtils.isEmpty(sourceServiceNamespace) && !StringUtils.isEmpty(sourceServiceName)) {
argument = Argument.buildCallerService(sourceServiceNamespace, sourceServiceName);
}
break;
case CALLER_IP:
InetSocketAddress remoteAddress = request.getRequest().getRemoteAddress();
argument = Argument.buildCallerIP(remoteAddress != null ? remoteAddress.getAddress().getHostAddress() : StringUtils.EMPTY);
break;
default:
break;
}
return argument;
}).filter(Objects::nonNull).collect(Collectors.toSet());
}
private Map<String, String> getCustomResolvedLabels(ServerWebExchange request) {
if (labelResolver != null) {
try {
return labelResolver.resolve(request);
}
catch (Throwable e) {
LOG.error("resolve custom label failed. resolver = {}", labelResolver.getClass().getName(), e);
}
}
return Collections.emptyMap();
}
}

@ -1,123 +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.ratelimit.resolver;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.polaris.context.ServiceRuleManager;
import com.tencent.cloud.polaris.ratelimit.filter.QuotaCheckServletFilter;
import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelServletResolver;
import com.tencent.polaris.ratelimit.api.rpc.Argument;
import com.tencent.polaris.specification.api.v1.traffic.manage.RateLimitProto;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import static com.tencent.cloud.common.constant.MetadataConstant.DefaultMetadata.DEFAULT_METADATA_SOURCE_SERVICE_NAME;
import static com.tencent.cloud.common.constant.MetadataConstant.DefaultMetadata.DEFAULT_METADATA_SOURCE_SERVICE_NAMESPACE;
/**
* resolve arguments from rate limit rule for Servlet.
*
* @author seansyyu 2023-03-09
*/
public class RateLimitRuleArgumentServletResolver {
private static final Logger LOG = LoggerFactory.getLogger(QuotaCheckServletFilter.class);
private final ServiceRuleManager serviceRuleManager;
private final PolarisRateLimiterLabelServletResolver labelResolver;
public RateLimitRuleArgumentServletResolver(ServiceRuleManager serviceRuleManager, PolarisRateLimiterLabelServletResolver labelResolver) {
this.serviceRuleManager = serviceRuleManager;
this.labelResolver = labelResolver;
}
public Set<Argument> getArguments(HttpServletRequest request, String namespace, String service) {
RateLimitProto.RateLimit rateLimitRule = serviceRuleManager.getServiceRateLimitRule(namespace, service);
if (rateLimitRule == null) {
return Collections.emptySet();
}
List<RateLimitProto.Rule> rules = rateLimitRule.getRulesList();
if (CollectionUtils.isEmpty(rules)) {
return Collections.emptySet();
}
return rules.stream()
.flatMap(rule -> rule.getArgumentsList().stream())
.map(matchArgument -> {
String matchKey = matchArgument.getKey();
Argument argument = null;
switch (matchArgument.getType()) {
case CUSTOM:
argument = StringUtils.isBlank(matchKey) ? null :
Argument.buildCustom(matchKey, Optional.ofNullable(getCustomResolvedLabels(request).get(matchKey)).orElse(StringUtils.EMPTY));
break;
case METHOD:
argument = Argument.buildMethod(request.getMethod());
break;
case HEADER:
argument = StringUtils.isBlank(matchKey) ? null :
Argument.buildHeader(matchKey, Optional.ofNullable(request.getHeader(matchKey)).orElse(StringUtils.EMPTY));
break;
case QUERY:
argument = StringUtils.isBlank(matchKey) ? null :
Argument.buildQuery(matchKey, Optional.ofNullable(request.getParameter(matchKey)).orElse(StringUtils.EMPTY));
break;
case CALLER_SERVICE:
String sourceServiceNamespace = MetadataContextHolder.getDisposableMetadata(DEFAULT_METADATA_SOURCE_SERVICE_NAMESPACE, true).orElse(StringUtils.EMPTY);
String sourceServiceName = MetadataContextHolder.getDisposableMetadata(DEFAULT_METADATA_SOURCE_SERVICE_NAME, true).orElse(StringUtils.EMPTY);
if (!StringUtils.isEmpty(sourceServiceNamespace) && !StringUtils.isEmpty(sourceServiceName)) {
argument = Argument.buildCallerService(sourceServiceNamespace, sourceServiceName);
}
break;
case CALLER_IP:
argument = Argument.buildCallerIP(Optional.ofNullable(request.getRemoteAddr()).orElse(StringUtils.EMPTY));
break;
default:
break;
}
return argument;
}).filter(Objects::nonNull).collect(Collectors.toSet());
}
private Map<String, String> getCustomResolvedLabels(HttpServletRequest request) {
if (labelResolver != null) {
try {
return labelResolver.resolve(request);
}
catch (Throwable e) {
LOG.error("resolve custom label failed. resolver = {}", labelResolver.getClass().getName(), e);
}
}
return Collections.emptyMap();
}
}

@ -1,38 +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.ratelimit.spi;
import java.util.Map;
import org.springframework.web.server.ServerWebExchange;
/**
* Resolve custom label from request. The label used for rate limit params.
*
* @author lepdou 2022-03-31
*/
public interface PolarisRateLimiterLabelReactiveResolver {
/**
* Resolve custom label from request.
* @param exchange the http request
* @return resolved labels
*/
Map<String, String> resolve(ServerWebExchange exchange);
}

@ -0,0 +1,44 @@
/*
* 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.ratelimit.tsf;
import com.tencent.cloud.common.tsf.ConditionalOnTsfConsulEnabled;
import com.tencent.cloud.polaris.context.config.extend.consul.ConsulProperties;
import com.tencent.cloud.polaris.context.config.extend.tsf.TsfCoreProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
/**
* Auto configuration of TSF rate limit.
*
* @author Haotian Zhang
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnTsfConsulEnabled
public class TsfRateLimitAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public TsfRateLimitConfigModifier tsfRateLimitConfigModifier(TsfCoreProperties tsfCoreProperties,
ConsulProperties consulProperties, Environment environment) {
return new TsfRateLimitConfigModifier(tsfCoreProperties, consulProperties, environment);
}
}

@ -13,26 +13,22 @@
* 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.ratelimit.spi;
package com.tencent.cloud.polaris.ratelimit.tsf;
import java.util.Map;
import com.tencent.cloud.common.tsf.ConditionalOnTsfConsulEnabled;
import javax.servlet.http.HttpServletRequest;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* Resolve custom label from request. The label used for rate limit params.
* Bootstrap configuration for TSF rate limit.
*
* @author lepdou 2022-03-31
* @author Haotian Zhang
*/
public interface PolarisRateLimiterLabelServletResolver {
/**
* Resolve custom label from request.
* @param request the http request
* @return resolved labels
*/
Map<String, String> resolve(HttpServletRequest request);
@Configuration(proxyBeanMethods = false)
@ConditionalOnTsfConsulEnabled
@Import(TsfRateLimitAutoConfiguration.class)
public class TsfRateLimitBootstrapConfiguration {
}

@ -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.ratelimit.tsf;
import java.util.Map;
import com.tencent.cloud.common.constant.OrderConstant;
import com.tencent.cloud.polaris.context.PolarisConfigModifier;
import com.tencent.cloud.polaris.context.config.extend.consul.ConsulProperties;
import com.tencent.cloud.polaris.context.config.extend.tsf.TsfContextUtils;
import com.tencent.cloud.polaris.context.config.extend.tsf.TsfCoreProperties;
import com.tencent.polaris.factory.config.ConfigurationImpl;
import com.tencent.polaris.ratelimit.client.sync.tsf.TsfRateLimitConstants;
import org.springframework.core.env.Environment;
/**
* Config modifier for TSF rate limit.
*
* @author Haotian Zhang
*/
public class TsfRateLimitConfigModifier implements PolarisConfigModifier {
private final TsfCoreProperties tsfCoreProperties;
private final ConsulProperties consulProperties;
private final Environment environment;
public TsfRateLimitConfigModifier(TsfCoreProperties tsfCoreProperties, ConsulProperties consulProperties,
Environment environment) {
this.tsfCoreProperties = tsfCoreProperties;
this.consulProperties = consulProperties;
this.environment = environment;
}
@Override
public void modify(ConfigurationImpl configuration) {
if (TsfContextUtils.isTsfConsulEnabled(environment)) {
Map<String, String> metadata = configuration.getProvider().getRateLimit().getMetadata();
metadata.put(TsfRateLimitConstants.RATE_LIMIT_MASTER_IP_KEY, tsfCoreProperties.getRatelimitMasterIp());
metadata.put(TsfRateLimitConstants.RATE_LIMIT_MASTER_PORT_KEY, String.valueOf(tsfCoreProperties.getRatelimitMasterPort()));
metadata.put(TsfRateLimitConstants.SERVICE_NAME_KEY, tsfCoreProperties.getServiceName());
metadata.put(TsfRateLimitConstants.INSTANCE_ID_KEY, tsfCoreProperties.getInstanceId());
metadata.put(TsfRateLimitConstants.TOKEN_KEY, consulProperties.getAclToken());
}
}
@Override
public int getOrder() {
return OrderConstant.Modifier.RATE_LIMIT_ORDER;
}
}

@ -17,12 +17,9 @@
package com.tencent.cloud.polaris.ratelimit.utils;
import java.util.Map;
import java.util.Set;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.polaris.api.plugin.ratelimiter.QuotaResult;
import com.tencent.polaris.ratelimit.api.core.LimitAPI;
import com.tencent.polaris.ratelimit.api.rpc.Argument;
import com.tencent.polaris.ratelimit.api.rpc.QuotaRequest;
import com.tencent.polaris.ratelimit.api.rpc.QuotaResponse;
import org.slf4j.Logger;
@ -40,34 +37,13 @@ public final class QuotaCheckUtils {
private QuotaCheckUtils() {
}
@Deprecated
public static QuotaResponse getQuota(LimitAPI limitAPI, String namespace, String service, int count,
Map<String, String> labels, String method) {
// build quota request
QuotaRequest quotaRequest = new QuotaRequest();
quotaRequest.setNamespace(namespace);
quotaRequest.setService(service);
quotaRequest.setCount(count);
quotaRequest.setLabels(labels);
quotaRequest.setMethod(method);
try {
return limitAPI.getQuota(quotaRequest);
}
catch (Throwable throwable) {
LOG.error("fail to invoke getQuota of LimitAPI with QuotaRequest[{}].", quotaRequest, throwable);
return new QuotaResponse(new QuotaResult(QuotaResult.Code.QuotaResultOk, 0, "get quota failed"));
}
}
public static QuotaResponse getQuota(LimitAPI limitAPI, String namespace, String service, int count,
Set<Argument> arguments, String method) {
public static QuotaResponse getQuota(LimitAPI limitAPI, String namespace, String service, int count, String method) {
// build quota request
QuotaRequest quotaRequest = new QuotaRequest();
quotaRequest.setNamespace(namespace);
quotaRequest.setService(service);
quotaRequest.setCount(count);
quotaRequest.setArguments(arguments);
quotaRequest.setMetadataContext(MetadataContextHolder.get());
quotaRequest.setMethod(method);
try {

@ -18,9 +18,17 @@
package com.tencent.cloud.polaris.ratelimit.utils;
import java.util.HashMap;
import java.util.Map;
import com.tencent.cloud.common.util.ResourceFileUtils;
import com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitProperties;
import com.tencent.cloud.polaris.ratelimit.constant.RateLimitConstant;
import com.tencent.polaris.api.plugin.stat.TraceConstants;
import com.tencent.polaris.api.utils.CollectionUtils;
import com.tencent.polaris.assembly.api.AssemblyAPI;
import com.tencent.polaris.assembly.api.pojo.TraceAttributes;
import com.tencent.polaris.ratelimit.api.rpc.QuotaResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -63,4 +71,33 @@ public final class RateLimitUtils {
return RateLimitConstant.QUOTA_LIMITED_INFO;
}
public static void reportTrace(AssemblyAPI assemblyAPI, String ruleId) {
try {
if (assemblyAPI != null) {
Map<String, String> attributes = new HashMap<>();
attributes.put(TraceConstants.RateLimitRuleId, ruleId);
TraceAttributes traceAttributes = new TraceAttributes();
traceAttributes.setAttributes(attributes);
traceAttributes.setAttributeLocation(TraceAttributes.AttributeLocation.SPAN);
assemblyAPI.updateTraceAttributes(traceAttributes);
}
}
catch (Throwable throwable) {
LOG.warn("[RateLimit] Report rule id {} to trace error.", ruleId, throwable);
}
}
public static void release(QuotaResponse quotaResponse) {
if (quotaResponse != null && CollectionUtils.isNotEmpty(quotaResponse.getReleaseList())) {
for (Runnable release : quotaResponse.getReleaseList()) {
try {
release.run();
}
catch (Throwable throwable) {
LOG.warn("[RateLimit] Release error.", throwable);
}
}
}
}
}

@ -1,6 +1,8 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitAutoConfiguration,\
com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitPropertiesAutoConfiguration,\
com.tencent.cloud.polaris.ratelimit.endpoint.PolarisRateLimitRuleEndpointAutoConfiguration
com.tencent.cloud.polaris.ratelimit.endpoint.PolarisRateLimitRuleEndpointAutoConfiguration,\
com.tencent.cloud.polaris.ratelimit.tsf.TsfRateLimitAutoConfiguration
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitPropertiesBootstrapConfiguration
com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitPropertiesBootstrapConfiguration,\
com.tencent.cloud.polaris.ratelimit.tsf.TsfRateLimitBootstrapConfiguration

@ -17,15 +17,16 @@
package com.tencent.cloud.polaris.context;
import com.google.protobuf.StringValue;
import com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitProperties;
import com.tencent.cloud.polaris.ratelimit.filter.QuotaCheckServletFilter;
import com.tencent.cloud.polaris.ratelimit.resolver.RateLimitRuleArgumentServletResolver;
import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLimitedFallback;
import com.tencent.polaris.api.pojo.ServiceKey;
import com.tencent.polaris.ratelimit.api.core.LimitAPI;
import com.tencent.polaris.ratelimit.api.rpc.QuotaResponse;
import com.tencent.polaris.ratelimit.api.rpc.QuotaResultCode;
import com.tencent.polaris.ratelimit.factory.LimitAPIFactory;
import com.tencent.polaris.specification.api.v1.traffic.manage.RateLimitProto;
import com.tencent.polaris.test.mock.discovery.NamingServer;
import com.tencent.polaris.test.mock.discovery.NamingService;
import org.junit.jupiter.api.AfterAll;
@ -118,6 +119,13 @@ public class CalleeControllerTests {
QuotaResponse quotaResponse = mock(QuotaResponse.class);
when(quotaResponse.getCode()).thenReturn(QuotaResultCode.QuotaResultLimited);
when(quotaResponse.getInfo()).thenReturn("Testing rate limit after 10 times success.");
RateLimitProto.Rule rule = mock(RateLimitProto.Rule.class);
when(rule.getId()).thenReturn(StringValue.of("rate-test"));
RateLimitProto.CustomResponse customResponse = mock(RateLimitProto.CustomResponse.class);
when(customResponse.getBody()).thenReturn("limited");
when(rule.getCustomResponse()).thenReturn(customResponse);
when(quotaResponse.getActiveRule()).thenReturn(rule);
when(quotaResponse.getActiveRuleName()).thenReturn("rate-test");
when(limitAPI.getQuota(any())).thenReturn(quotaResponse);
}
String result = restTemplate.getForObject(url, String.class);
@ -126,7 +134,7 @@ public class CalleeControllerTests {
}
catch (RestClientException e) {
if (e instanceof TooManyRequests) {
System.out.println(((TooManyRequests) e).getResponseBodyAsString());
assertThat(((TooManyRequests) e).getResponseBodyAsString()).isEqualTo("limited");
hasLimited = true;
}
else {
@ -157,10 +165,8 @@ public class CalleeControllerTests {
@Primary
public QuotaCheckServletFilter quotaCheckFilter(LimitAPI limitAPI,
PolarisRateLimitProperties polarisRateLimitProperties,
RateLimitRuleArgumentServletResolver rateLimitRuleArgumentResolver,
@Autowired(required = false) PolarisRateLimiterLimitedFallback polarisRateLimiterLimitedFallback) {
return new QuotaCheckServletFilter(limitAPI, polarisRateLimitProperties,
rateLimitRuleArgumentResolver, polarisRateLimiterLimitedFallback);
return new QuotaCheckServletFilter(limitAPI, null, polarisRateLimitProperties, polarisRateLimiterLimitedFallback);
}
}
}

@ -1,99 +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.ratelimit;
import java.util.Set;
import com.google.protobuf.StringValue;
import com.tencent.cloud.polaris.context.ServiceRuleManager;
import com.tencent.polaris.specification.api.v1.model.ModelProto;
import com.tencent.polaris.specification.api.v1.traffic.manage.RateLimitProto;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* Test for {@link RateLimitRuleLabelResolver}.
*
* @author Haotian Zhang
*/
@ExtendWith(MockitoExtension.class)
public class RateLimitRuleLabelResolverTest {
private RateLimitRuleLabelResolver rateLimitRuleLabelResolver;
@BeforeEach
void setUp() {
ServiceRuleManager serviceRuleManager = mock(ServiceRuleManager.class);
when(serviceRuleManager.getServiceRateLimitRule(any(), anyString())).thenAnswer(invocationOnMock -> {
String serviceName = invocationOnMock.getArgument(1).toString();
if (serviceName.equals("TestApp1")) {
return null;
}
else if (serviceName.equals("TestApp2")) {
return RateLimitProto.RateLimit.newBuilder().build();
}
else if (serviceName.equals("TestApp3")) {
RateLimitProto.Rule rule = RateLimitProto.Rule.newBuilder().build();
return RateLimitProto.RateLimit.newBuilder().addRules(rule).build();
}
else {
ModelProto.MatchString matchString = ModelProto.MatchString.newBuilder()
.setType(ModelProto.MatchString.MatchStringType.EXACT)
.setValue(StringValue.of("value"))
.setValueType(ModelProto.MatchString.ValueType.TEXT).build();
RateLimitProto.Rule rule = RateLimitProto.Rule.newBuilder()
.putLabels("${http.method}", matchString).build();
return RateLimitProto.RateLimit.newBuilder().addRules(rule).build();
}
});
rateLimitRuleLabelResolver = new RateLimitRuleLabelResolver(serviceRuleManager);
}
@Test
public void testGetExpressionLabelKeys() {
// rateLimitRule == null
String serviceName = "TestApp1";
Set<String> labelKeys = rateLimitRuleLabelResolver.getExpressionLabelKeys(null, serviceName);
assertThat(labelKeys).isEmpty();
// CollectionUtils.isEmpty(rules)
serviceName = "TestApp2";
labelKeys = rateLimitRuleLabelResolver.getExpressionLabelKeys(null, serviceName);
assertThat(labelKeys).isEmpty();
// CollectionUtils.isEmpty(labels)
serviceName = "TestApp3";
labelKeys = rateLimitRuleLabelResolver.getExpressionLabelKeys(null, serviceName);
assertThat(labelKeys).isEmpty();
// Has labels
serviceName = "TestApp4";
labelKeys = rateLimitRuleLabelResolver.getExpressionLabelKeys(null, serviceName);
assertThat(labelKeys).isNotEmpty();
assertThat(labelKeys).contains("${http.method}");
}
}

@ -20,8 +20,6 @@ package com.tencent.cloud.polaris.ratelimit.config;
import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration;
import com.tencent.cloud.polaris.ratelimit.filter.QuotaCheckReactiveFilter;
import com.tencent.cloud.polaris.ratelimit.filter.QuotaCheckServletFilter;
import com.tencent.cloud.polaris.ratelimit.resolver.RateLimitRuleArgumentReactiveResolver;
import com.tencent.cloud.polaris.ratelimit.resolver.RateLimitRuleArgumentServletResolver;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
@ -53,12 +51,10 @@ public class PolarisRateLimitAutoConfigurationTest {
PolarisRateLimitProperties.class,
PolarisRateLimitAutoConfiguration.class))
.run(context -> {
assertThat(context).doesNotHaveBean(RateLimitRuleArgumentServletResolver.class);
assertThat(context).doesNotHaveBean(RateLimitRuleArgumentReactiveResolver.class);
assertThat(context).doesNotHaveBean(PolarisRateLimitAutoConfiguration.QuotaCheckFilterConfig.class);
assertThat(context).doesNotHaveBean(QuotaCheckServletFilter.class);
assertThat(context).doesNotHaveBean(FilterRegistrationBean.class);
assertThat(context).doesNotHaveBean(PolarisRateLimitAutoConfiguration.MetadataReactiveFilterConfig.class);
assertThat(context).doesNotHaveBean(PolarisRateLimitAutoConfiguration.QuotaCheckReactiveFilterConfig.class);
assertThat(context).doesNotHaveBean(QuotaCheckReactiveFilter.class);
});
}
@ -71,13 +67,11 @@ public class PolarisRateLimitAutoConfigurationTest {
PolarisRateLimitProperties.class,
PolarisRateLimitAutoConfiguration.class))
.run(context -> {
assertThat(context).hasSingleBean(RateLimitRuleArgumentServletResolver.class);
assertThat(context).hasSingleBean(PolarisRateLimitAutoConfiguration.QuotaCheckFilterConfig.class);
assertThat(context).hasSingleBean(QuotaCheckServletFilter.class);
assertThat(context).hasSingleBean(FilterRegistrationBean.class);
assertThat(context).doesNotHaveBean(PolarisRateLimitAutoConfiguration.MetadataReactiveFilterConfig.class);
assertThat(context).doesNotHaveBean(PolarisRateLimitAutoConfiguration.QuotaCheckReactiveFilterConfig.class);
assertThat(context).doesNotHaveBean(QuotaCheckReactiveFilter.class);
assertThat(context).doesNotHaveBean(RateLimitRuleArgumentReactiveResolver.class);
});
}
@ -89,12 +83,10 @@ public class PolarisRateLimitAutoConfigurationTest {
PolarisRateLimitProperties.class,
PolarisRateLimitAutoConfiguration.class))
.run(context -> {
assertThat(context).doesNotHaveBean(RateLimitRuleArgumentServletResolver.class);
assertThat(context).hasSingleBean(RateLimitRuleArgumentReactiveResolver.class);
assertThat(context).doesNotHaveBean(PolarisRateLimitAutoConfiguration.QuotaCheckFilterConfig.class);
assertThat(context).doesNotHaveBean(QuotaCheckServletFilter.class);
assertThat(context).doesNotHaveBean(FilterRegistrationBean.class);
assertThat(context).hasSingleBean(PolarisRateLimitAutoConfiguration.MetadataReactiveFilterConfig.class);
assertThat(context).hasSingleBean(PolarisRateLimitAutoConfiguration.QuotaCheckReactiveFilterConfig.class);
assertThat(context).hasSingleBean(QuotaCheckReactiveFilter.class);
});
}

@ -22,7 +22,6 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;
@ -32,8 +31,6 @@ import com.tencent.cloud.common.constant.OrderConstant;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.polaris.context.ServiceRuleManager;
import com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitProperties;
import com.tencent.cloud.polaris.ratelimit.resolver.RateLimitRuleArgumentReactiveResolver;
import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelReactiveResolver;
import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLimitedFallback;
import com.tencent.polaris.api.plugin.ratelimiter.QuotaResult;
import com.tencent.polaris.ratelimit.api.core.LimitAPI;
@ -74,8 +71,6 @@ import static org.mockito.Mockito.when;
@SpringBootTest(classes = QuotaCheckReactiveFilterTest.TestApplication.class,
properties = {"spring.cloud.polaris.namespace=Test", "spring.cloud.polaris.service=TestApp"})
public class QuotaCheckReactiveFilterTest {
private final PolarisRateLimiterLabelReactiveResolver labelResolver =
exchange -> Collections.singletonMap("xxx", "xxx");
private QuotaCheckReactiveFilter quotaCheckReactiveFilter;
private QuotaCheckReactiveFilter quotaCheckWithRateLimiterLimitedFallbackReactiveFilter;
private PolarisRateLimiterLimitedFallback polarisRateLimiterLimitedFallback;
@ -123,10 +118,10 @@ public class QuotaCheckReactiveFilterTest {
RateLimitProto.RateLimit rateLimit = RateLimitProto.RateLimit.newBuilder().addRules(rateLimitRule).build();
when(serviceRuleManager.getServiceRateLimitRule(anyString(), anyString())).thenReturn(rateLimit);
RateLimitRuleArgumentReactiveResolver rateLimitRuleArgumentReactiveResolver = new RateLimitRuleArgumentReactiveResolver(serviceRuleManager, labelResolver);
this.quotaCheckReactiveFilter = new QuotaCheckReactiveFilter(limitAPI, polarisRateLimitProperties, rateLimitRuleArgumentReactiveResolver, null);
this.quotaCheckReactiveFilter = new QuotaCheckReactiveFilter(limitAPI, null, polarisRateLimitProperties, null);
this.polarisRateLimiterLimitedFallback = new JsonPolarisRateLimiterLimitedFallback();
this.quotaCheckWithRateLimiterLimitedFallbackReactiveFilter = new QuotaCheckReactiveFilter(limitAPI, polarisRateLimitWithHtmlRejectTipsProperties, rateLimitRuleArgumentReactiveResolver, polarisRateLimiterLimitedFallback);
this.quotaCheckWithRateLimiterLimitedFallbackReactiveFilter = new QuotaCheckReactiveFilter(limitAPI, null,
polarisRateLimitWithHtmlRejectTipsProperties, polarisRateLimiterLimitedFallback);
}
@Test

@ -23,19 +23,18 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.stream.Collectors;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.StringValue;
import com.google.protobuf.util.JsonFormat;
import com.tencent.cloud.common.constant.HeaderConstant;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.polaris.context.ServiceRuleManager;
import com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitProperties;
import com.tencent.cloud.polaris.ratelimit.resolver.RateLimitRuleArgumentServletResolver;
import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelServletResolver;
import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLimitedFallback;
import com.tencent.polaris.api.plugin.ratelimiter.QuotaResult;
import com.tencent.polaris.ratelimit.api.core.LimitAPI;
@ -69,12 +68,10 @@ import static org.mockito.Mockito.when;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = QuotaCheckServletFilterTest.TestApplication.class,
properties = {
"spring.cloud.polaris.namespace=Test", "spring.cloud.polaris.service=TestApp"
})
"spring.cloud.polaris.namespace=Test", "spring.cloud.polaris.service=TestApp"
})
public class QuotaCheckServletFilterTest {
private final PolarisRateLimiterLabelServletResolver labelResolver =
exchange -> Collections.singletonMap("xxx", "xxx");
private QuotaCheckServletFilter quotaCheckServletFilter;
private QuotaCheckServletFilter quotaCheckWithHtmlRejectTipsServletFilter;
private QuotaCheckServletFilter quotaCheckWithRateLimiterLimitedFallbackFilter;
@ -95,7 +92,8 @@ public class QuotaCheckServletFilterTest {
}
else if (serviceName.equals("TestApp3")) {
QuotaResponse response = new QuotaResponse(new QuotaResult(QuotaResult.Code.QuotaResultLimited, 0, "QuotaResultLimited"));
response.setActiveRule(RateLimitProto.Rule.newBuilder().build());
response.setActiveRule(RateLimitProto.Rule.newBuilder()
.setName(StringValue.newBuilder().setValue("MOCK_RULE").build()).build());
return response;
}
else {
@ -113,19 +111,22 @@ public class QuotaCheckServletFilterTest {
ServiceRuleManager serviceRuleManager = mock(ServiceRuleManager.class);
RateLimitProto.Rule.Builder ratelimitRuleBuilder = RateLimitProto.Rule.newBuilder();
InputStream inputStream = QuotaCheckServletFilterTest.class.getClassLoader().getResourceAsStream("ratelimit.json");
String json = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).lines().collect(Collectors.joining(""));
RateLimitProto.Rule.Builder ratelimitRuleBuilder = RateLimitProto.Rule.newBuilder();
InputStream inputStream = QuotaCheckServletFilterTest.class.getClassLoader()
.getResourceAsStream("ratelimit.json");
String json = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).lines()
.collect(Collectors.joining(""));
JsonFormat.parser().ignoringUnknownFields().merge(json, ratelimitRuleBuilder);
RateLimitProto.Rule rateLimitRule = ratelimitRuleBuilder.build();
RateLimitProto.RateLimit rateLimit = RateLimitProto.RateLimit.newBuilder().addRules(rateLimitRule).build();
when(serviceRuleManager.getServiceRateLimitRule(anyString(), anyString())).thenReturn(rateLimit);
RateLimitRuleArgumentServletResolver rateLimitRuleArgumentServletResolver = new RateLimitRuleArgumentServletResolver(serviceRuleManager, labelResolver);
this.quotaCheckServletFilter = new QuotaCheckServletFilter(limitAPI, polarisRateLimitProperties, rateLimitRuleArgumentServletResolver, null);
this.quotaCheckWithHtmlRejectTipsServletFilter = new QuotaCheckServletFilter(limitAPI, polarisRateLimitWithHtmlRejectTipsProperties, rateLimitRuleArgumentServletResolver, null);
this.quotaCheckServletFilter = new QuotaCheckServletFilter(limitAPI, null, polarisRateLimitProperties, null);
this.quotaCheckWithHtmlRejectTipsServletFilter = new QuotaCheckServletFilter(limitAPI, null,
polarisRateLimitWithHtmlRejectTipsProperties, null);
this.polarisRateLimiterLimitedFallback = new JsonPolarisRateLimiterLimitedFallback();
this.quotaCheckWithRateLimiterLimitedFallbackFilter = new QuotaCheckServletFilter(limitAPI, polarisRateLimitWithHtmlRejectTipsProperties, rateLimitRuleArgumentServletResolver, polarisRateLimiterLimitedFallback);
this.quotaCheckWithRateLimiterLimitedFallbackFilter = new QuotaCheckServletFilter(limitAPI, null,
polarisRateLimitWithHtmlRejectTipsProperties, polarisRateLimiterLimitedFallback);
}
@Test
@ -182,6 +183,7 @@ public class QuotaCheckServletFilterTest {
quotaCheckServletFilter.doFilterInternal(request, testApp3Response, filterChain);
assertThat(testApp3Response.getStatus()).isEqualTo(419);
assertThat(testApp3Response.getContentAsString()).isEqualTo("RejectRequestTips提示消息");
assertThat(testApp3Response.getHeader(HeaderConstant.INTERNAL_ACTIVE_RULE_NAME)).isEqualTo("MOCK_RULE");
MockHttpServletResponse testApp3Response2 = new MockHttpServletResponse();
quotaCheckWithHtmlRejectTipsServletFilter.doFilterInternal(request, testApp3Response2, filterChain);

@ -1,144 +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.ratelimit.resolver;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.util.JsonFormat;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.polaris.context.ServiceRuleManager;
import com.tencent.cloud.polaris.ratelimit.filter.QuotaCheckServletFilterTest;
import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelReactiveResolver;
import com.tencent.polaris.ratelimit.api.rpc.Argument;
import com.tencent.polaris.specification.api.v1.traffic.manage.RateLimitProto;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
import org.springframework.mock.web.server.MockServerWebExchange;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.web.server.ServerWebExchange;
import static com.tencent.cloud.common.constant.MetadataConstant.DefaultMetadata.DEFAULT_METADATA_SOURCE_SERVICE_NAME;
import static com.tencent.cloud.common.constant.MetadataConstant.DefaultMetadata.DEFAULT_METADATA_SOURCE_SERVICE_NAMESPACE;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = RateLimitRuleArgumentReactiveResolverTest.TestApplication.class,
properties = {
"spring.cloud.polaris.namespace=Test", "spring.cloud.polaris.service=TestApp"
})
public class RateLimitRuleArgumentReactiveResolverTest {
private final PolarisRateLimiterLabelReactiveResolver labelResolver =
exchange -> Collections.singletonMap("xxx", "xxx");
private final PolarisRateLimiterLabelReactiveResolver labelResolverEx =
exchange -> {
throw new RuntimeException();
};
private RateLimitRuleArgumentReactiveResolver rateLimitRuleArgumentReactiveResolver1;
private RateLimitRuleArgumentReactiveResolver rateLimitRuleArgumentReactiveResolver2;
private RateLimitRuleArgumentReactiveResolver rateLimitRuleArgumentReactiveResolver3;
private RateLimitRuleArgumentReactiveResolver rateLimitRuleArgumentReactiveResolver4;
@BeforeEach
void setUp() throws InvalidProtocolBufferException {
MetadataContext.LOCAL_NAMESPACE = "TEST";
ServiceRuleManager serviceRuleManager = mock(ServiceRuleManager.class);
RateLimitProto.Rule.Builder ratelimitRuleBuilder = RateLimitProto.Rule.newBuilder();
InputStream inputStream = QuotaCheckServletFilterTest.class.getClassLoader().getResourceAsStream("ratelimit.json");
String json = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).lines().collect(Collectors.joining(""));
JsonFormat.parser().ignoringUnknownFields().merge(json, ratelimitRuleBuilder);
RateLimitProto.Rule rateLimitRule = ratelimitRuleBuilder.build();
RateLimitProto.RateLimit rateLimit = RateLimitProto.RateLimit.newBuilder().addRules(rateLimitRule).build();
when(serviceRuleManager.getServiceRateLimitRule(anyString(), anyString())).thenReturn(rateLimit);
// normal
this.rateLimitRuleArgumentReactiveResolver1 = new RateLimitRuleArgumentReactiveResolver(serviceRuleManager, labelResolver);
// ex
this.rateLimitRuleArgumentReactiveResolver2 = new RateLimitRuleArgumentReactiveResolver(serviceRuleManager, labelResolverEx);
// null
ServiceRuleManager serviceRuleManager1 = mock(ServiceRuleManager.class);
when(serviceRuleManager1.getServiceRateLimitRule(anyString(), anyString())).thenReturn(null);
this.rateLimitRuleArgumentReactiveResolver3 = new RateLimitRuleArgumentReactiveResolver(serviceRuleManager1, labelResolver);
// null 2
ServiceRuleManager serviceRuleManager2 = mock(ServiceRuleManager.class);
RateLimitProto.RateLimit rateLimit2 = RateLimitProto.RateLimit.newBuilder().build();
when(serviceRuleManager2.getServiceRateLimitRule(anyString(), anyString())).thenReturn(rateLimit2);
this.rateLimitRuleArgumentReactiveResolver4 = new RateLimitRuleArgumentReactiveResolver(serviceRuleManager2, labelResolver);
}
@Test
public void testGetRuleArguments() {
// Mock request
MetadataContext.LOCAL_SERVICE = "Test";
// Mock request
MockServerHttpRequest request = MockServerHttpRequest.get("http://127.0.0.1:8080/test")
.remoteAddress(new InetSocketAddress("127.0.0.1", 8080))
.header("xxx", "xxx")
.queryParam("yyy", "yyy")
.build();
ServerWebExchange exchange = MockServerWebExchange.from(request);
MetadataContext metadataContext = new MetadataContext();
metadataContext.setUpstreamDisposableMetadata(new HashMap<String, String>() {{
put(DEFAULT_METADATA_SOURCE_SERVICE_NAMESPACE, MetadataContext.LOCAL_NAMESPACE);
put(DEFAULT_METADATA_SOURCE_SERVICE_NAME, MetadataContext.LOCAL_SERVICE);
}});
MetadataContextHolder.set(metadataContext);
Set<Argument> arguments = rateLimitRuleArgumentReactiveResolver1.getArguments(exchange, MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE);
Set<Argument> exceptRes = new HashSet<>();
exceptRes.add(Argument.buildMethod("GET"));
exceptRes.add(Argument.buildHeader("xxx", "xxx"));
exceptRes.add(Argument.buildQuery("yyy", "yyy"));
exceptRes.add(Argument.buildCallerIP("127.0.0.1"));
exceptRes.add(Argument.buildCustom("xxx", "xxx"));
exceptRes.add(Argument.buildCallerService(MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE));
assertThat(arguments).isEqualTo(exceptRes);
rateLimitRuleArgumentReactiveResolver2.getArguments(exchange, MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE);
rateLimitRuleArgumentReactiveResolver3.getArguments(exchange, MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE);
rateLimitRuleArgumentReactiveResolver4.getArguments(exchange, MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE);
}
@SpringBootApplication
protected static class TestApplication {
}
}

@ -1,135 +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.ratelimit.resolver;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.util.JsonFormat;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.polaris.context.ServiceRuleManager;
import com.tencent.cloud.polaris.ratelimit.filter.QuotaCheckServletFilterTest;
import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelServletResolver;
import com.tencent.polaris.ratelimit.api.rpc.Argument;
import com.tencent.polaris.specification.api.v1.traffic.manage.RateLimitProto;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import static com.tencent.cloud.common.constant.MetadataConstant.DefaultMetadata.DEFAULT_METADATA_SOURCE_SERVICE_NAME;
import static com.tencent.cloud.common.constant.MetadataConstant.DefaultMetadata.DEFAULT_METADATA_SOURCE_SERVICE_NAMESPACE;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = RateLimitRuleArgumentServletResolverTest.TestApplication.class,
properties = {
"spring.cloud.polaris.namespace=Test", "spring.cloud.polaris.service=TestApp"
})
public class RateLimitRuleArgumentServletResolverTest {
private final PolarisRateLimiterLabelServletResolver labelResolver =
exchange -> Collections.singletonMap("xxx", "xxx");
private final PolarisRateLimiterLabelServletResolver labelResolverEx =
exchange -> {
throw new RuntimeException();
};
private RateLimitRuleArgumentServletResolver rateLimitRuleArgumentServletResolver1;
private RateLimitRuleArgumentServletResolver rateLimitRuleArgumentServletResolver2;
private RateLimitRuleArgumentServletResolver rateLimitRuleArgumentServletResolver3;
private RateLimitRuleArgumentServletResolver rateLimitRuleArgumentServletResolver4;
@BeforeEach
void setUp() throws InvalidProtocolBufferException {
MetadataContext.LOCAL_NAMESPACE = "TEST";
ServiceRuleManager serviceRuleManager = mock(ServiceRuleManager.class);
RateLimitProto.Rule.Builder ratelimitRuleBuilder = RateLimitProto.Rule.newBuilder();
InputStream inputStream = QuotaCheckServletFilterTest.class.getClassLoader().getResourceAsStream("ratelimit.json");
String json = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).lines().collect(Collectors.joining(""));
JsonFormat.parser().ignoringUnknownFields().merge(json, ratelimitRuleBuilder);
RateLimitProto.Rule rateLimitRule = ratelimitRuleBuilder.build();
RateLimitProto.RateLimit rateLimit = RateLimitProto.RateLimit.newBuilder().addRules(rateLimitRule).build();
when(serviceRuleManager.getServiceRateLimitRule(anyString(), anyString())).thenReturn(rateLimit);
// normal
this.rateLimitRuleArgumentServletResolver1 = new RateLimitRuleArgumentServletResolver(serviceRuleManager, labelResolver);
// ex
this.rateLimitRuleArgumentServletResolver2 = new RateLimitRuleArgumentServletResolver(serviceRuleManager, labelResolverEx);
// null
ServiceRuleManager serviceRuleManager1 = mock(ServiceRuleManager.class);
when(serviceRuleManager1.getServiceRateLimitRule(anyString(), anyString())).thenReturn(null);
this.rateLimitRuleArgumentServletResolver3 = new RateLimitRuleArgumentServletResolver(serviceRuleManager1, labelResolver);
// null 2
ServiceRuleManager serviceRuleManager2 = mock(ServiceRuleManager.class);
RateLimitProto.RateLimit rateLimit2 = RateLimitProto.RateLimit.newBuilder().build();
when(serviceRuleManager2.getServiceRateLimitRule(anyString(), anyString())).thenReturn(rateLimit2);
this.rateLimitRuleArgumentServletResolver4 = new RateLimitRuleArgumentServletResolver(serviceRuleManager2, labelResolver);
}
@Test
public void testGetRuleArguments() {
// Mock request
MetadataContext.LOCAL_SERVICE = "Test";
MockHttpServletRequest request = new MockHttpServletRequest(null, "GET", "/xxx");
request.setParameter("yyy", "yyy");
request.addHeader("xxx", "xxx");
MetadataContext metadataContext = new MetadataContext();
metadataContext.setUpstreamDisposableMetadata(new HashMap<String, String>() {{
put(DEFAULT_METADATA_SOURCE_SERVICE_NAMESPACE, MetadataContext.LOCAL_NAMESPACE);
put(DEFAULT_METADATA_SOURCE_SERVICE_NAME, MetadataContext.LOCAL_SERVICE);
}});
MetadataContextHolder.set(metadataContext);
Set<Argument> arguments = rateLimitRuleArgumentServletResolver1.getArguments(request, MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE);
Set<Argument> exceptRes = new HashSet<>();
exceptRes.add(Argument.buildMethod("GET"));
exceptRes.add(Argument.buildHeader("xxx", "xxx"));
exceptRes.add(Argument.buildQuery("yyy", "yyy"));
exceptRes.add(Argument.buildCallerIP("127.0.0.1"));
exceptRes.add(Argument.buildCustom("xxx", "xxx"));
exceptRes.add(Argument.buildCallerService(MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE));
assertThat(arguments).isEqualTo(exceptRes);
rateLimitRuleArgumentServletResolver2.getArguments(request, MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE);
rateLimitRuleArgumentServletResolver3.getArguments(request, MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE);
rateLimitRuleArgumentServletResolver4.getArguments(request, MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE);
}
@SpringBootApplication
protected static class TestApplication {
}
}

@ -17,9 +17,6 @@
package com.tencent.cloud.polaris.ratelimit.utils;
import java.util.HashMap;
import java.util.HashSet;
import com.tencent.polaris.api.plugin.ratelimiter.QuotaResult;
import com.tencent.polaris.ratelimit.api.core.LimitAPI;
import com.tencent.polaris.ratelimit.api.rpc.QuotaRequest;
@ -69,59 +66,28 @@ public class QuotaCheckUtilsTest {
public void testGetQuota() {
// Pass
String serviceName = "TestApp1";
QuotaResponse quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, new HashMap<>(), null);
assertThat(quotaResponse.getCode()).isEqualTo(QuotaResultCode.QuotaResultOk);
assertThat(quotaResponse.getWaitMs()).isEqualTo(0);
assertThat(quotaResponse.getInfo()).isEqualTo("QuotaResultOk");
// Unirate waiting 1000ms
serviceName = "TestApp2";
quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, new HashMap<>(), null);
assertThat(quotaResponse.getCode()).isEqualTo(QuotaResultCode.QuotaResultOk);
assertThat(quotaResponse.getWaitMs()).isEqualTo(1000);
assertThat(quotaResponse.getInfo()).isEqualTo("QuotaResultOk");
// Rate limited
serviceName = "TestApp3";
quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, new HashMap<>(), null);
assertThat(quotaResponse.getCode()).isEqualTo(QuotaResultCode.QuotaResultLimited);
assertThat(quotaResponse.getWaitMs()).isEqualTo(0);
assertThat(quotaResponse.getInfo()).isEqualTo("QuotaResultLimited");
// Exception
serviceName = "TestApp4";
quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, new HashMap<>(), null);
assertThat(quotaResponse.getCode()).isEqualTo(QuotaResultCode.QuotaResultOk);
assertThat(quotaResponse.getWaitMs()).isEqualTo(0);
assertThat(quotaResponse.getInfo()).isEqualTo("get quota failed");
}
@Test
public void testGetQuota2() {
// Pass
String serviceName = "TestApp1";
QuotaResponse quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, new HashSet<>(), null);
QuotaResponse quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, null);
assertThat(quotaResponse.getCode()).isEqualTo(QuotaResultCode.QuotaResultOk);
assertThat(quotaResponse.getWaitMs()).isEqualTo(0);
assertThat(quotaResponse.getInfo()).isEqualTo("QuotaResultOk");
// Unirate waiting 1000ms
serviceName = "TestApp2";
quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, new HashSet<>(), null);
quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, null);
assertThat(quotaResponse.getCode()).isEqualTo(QuotaResultCode.QuotaResultOk);
assertThat(quotaResponse.getWaitMs()).isEqualTo(1000);
assertThat(quotaResponse.getInfo()).isEqualTo("QuotaResultOk");
// Rate limited
serviceName = "TestApp3";
quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, new HashSet<>(), null);
quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, null);
assertThat(quotaResponse.getCode()).isEqualTo(QuotaResultCode.QuotaResultLimited);
assertThat(quotaResponse.getWaitMs()).isEqualTo(0);
assertThat(quotaResponse.getInfo()).isEqualTo("QuotaResultLimited");
// Exception
serviceName = "TestApp4";
quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, new HashSet<>(), null);
quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, null);
assertThat(quotaResponse.getCode()).isEqualTo(QuotaResultCode.QuotaResultOk);
assertThat(quotaResponse.getWaitMs()).isEqualTo(0);
assertThat(quotaResponse.getInfo()).isEqualTo("get quota failed");

@ -28,6 +28,8 @@ import com.tencent.polaris.metadata.core.MetadataContainer;
import com.tencent.polaris.metadata.core.MetadataProvider;
import com.tencent.polaris.metadata.core.MetadataType;
import com.tencent.polaris.metadata.core.TransitiveType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
@ -42,6 +44,8 @@ import static com.tencent.cloud.common.metadata.MetadataContext.FRAGMENT_UPSTREA
*/
public final class MetadataContextHolder {
private static final Logger LOG = LoggerFactory.getLogger(MetadataContextHolder.class);
private static StaticMetadataManager staticMetadataManager;
static {
@ -58,8 +62,14 @@ public final class MetadataContextHolder {
private static MetadataContext createMetadataManager() {
MetadataContext metadataManager = new MetadataContext();
if (staticMetadataManager == null) {
staticMetadataManager = ApplicationContextAwareUtils.getApplicationContext()
.getBean(StaticMetadataManager.class);
if (ApplicationContextAwareUtils.getApplicationContext() != null) {
staticMetadataManager = ApplicationContextAwareUtils.getApplicationContext()
.getBean(StaticMetadataManager.class);
}
else {
// for junit test.
return metadataManager;
}
}
// local custom metadata
MetadataContainer metadataContainer = metadataManager.getMetadataContainer(MetadataType.CUSTOM, false);

@ -43,7 +43,7 @@ public final class TsfContext {
return;
}
MetadataContext tsfCoreContext = MetadataContextHolder.get();
TransitiveType transitive = TransitiveType.NONE;
TransitiveType transitive = TransitiveType.DISPOSABLE;
if (null != flags) {
for (Tag.ControlFlag flag : flags) {
if (flag == Tag.ControlFlag.TRANSITIVE) {

@ -88,7 +88,10 @@
<system-stubs-jupiter.version>2.0.2</system-stubs-jupiter.version>
<!-- Maven Plugin Versions -->
<maven-javadoc-plugin.verison>3.3.0</maven-javadoc-plugin.verison>
<maven-source-plugin.version>3.2.0</maven-source-plugin.version>
<flatten-maven-plugin.version>1.3.0</flatten-maven-plugin.version>
<maven-gpg-plugin.version>3.0.1</maven-gpg-plugin.version>
</properties>
<dependencyManagement>

@ -36,6 +36,7 @@ public class CustomMetadata implements InstanceMetadataProvider {
public Map<String, String> getMetadata() {
Map<String, String> metadata = new HashMap<>();
metadata.put("k1", "v1");
metadata.put("lane", "lane1");
return metadata;
}

@ -1,63 +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.quickstart.callee.ratelimit;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelServletResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* resolver custom label from request.
*
* @author lepdou 2022-03-31
*/
@Component
public class CustomLabelResolver implements PolarisRateLimiterLabelServletResolver {
private static final Logger LOG = LoggerFactory.getLogger(CustomLabelResolver.class);
@Value("${label.key-value:}")
private String[] keyValues;
@Override
public Map<String, String> resolve(HttpServletRequest request) {
// rate limit by some request params. such as query params, headers ..
return getLabels(keyValues);
}
private Map<String, String> getLabels(String[] keyValues) {
Map<String, String> labels = new HashMap<>();
for (String kv : keyValues) {
String key = kv.substring(0, kv.indexOf(":"));
String value = kv.substring(kv.indexOf(":") + 1);
labels.put(key, value);
}
LOG.info("Current labels:{}", labels);
return labels;
}
}

@ -49,3 +49,8 @@ management:
- polaris-config
label:
key-value: user:zhangsan
logging:
file:
name: /sct-demo-logs/${spring.application.name}/root.log
level:
root: INFO

@ -36,6 +36,7 @@ public class CustomMetadata implements InstanceMetadataProvider {
public Map<String, String> getMetadata() {
Map<String, String> metadata = new HashMap<>();
metadata.put("k1", "v2");
metadata.put("lane", "lane2");
return metadata;
}

@ -1,60 +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.quickstart.callee.ratelimit;
import java.util.HashMap;
import java.util.Map;
import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelReactiveResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
/**
* resolver custom label from request.
*
* @author sean yu
*/
@Component
public class CustomLabelResolverReactive implements PolarisRateLimiterLabelReactiveResolver {
private static final Logger LOG = LoggerFactory.getLogger(CustomLabelResolverReactive.class);
@Value("${label.key-value:}")
private String[] keyValues;
@Override
public Map<String, String> resolve(ServerWebExchange exchange) {
// rate limit by some request params. such as query params, headers ..
return getLabels(keyValues);
}
private Map<String, String> getLabels(String[] keyValues) {
Map<String, String> labels = new HashMap<>();
for (String kv : keyValues) {
String key = kv.substring(0, kv.indexOf(":"));
String value = kv.substring(kv.indexOf(":") + 1);
labels.put(key, value);
}
LOG.info("Current labels:{}", labels);
return labels;
}
}

@ -48,3 +48,8 @@ management:
- polaris-config
label:
key-value: user2:lisi
logging:
file:
name: /sct-demo-logs/${spring.application.name}/root.log
level:
root: INFO

@ -18,6 +18,9 @@
package com.tencent.cloud.quickstart.caller;
import java.util.HashMap;
import java.util.Map;
import com.tencent.cloud.common.spi.InstanceMetadataProvider;
import org.springframework.stereotype.Component;
@ -28,6 +31,12 @@ import org.springframework.stereotype.Component;
@Component
public class CustomMetadataProvider implements InstanceMetadataProvider {
@Override
public Map<String, String> getMetadata() {
Map<String, String> metadata = new HashMap<>();
metadata.put("k1", "v1");
return metadata;
}
// @Override
// public String getRegion() {
// return "huadong";

@ -40,6 +40,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.function.client.WebClient;
@ -100,7 +101,12 @@ public class QuickstartCallerController {
HttpEntity<String> entity = new HttpEntity<>(headers);
// 使用 exchange 方法发送 GET 请求,并获取响应
return restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
try {
return restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
}
catch (HttpClientErrorException | HttpServerErrorException httpClientErrorException) {
return new ResponseEntity<>(httpClientErrorException.getResponseBodyAsString(), httpClientErrorException.getStatusCode());
}
}
/**
@ -121,32 +127,33 @@ public class QuickstartCallerController {
* Get information 30 times per 1 second.
*
* @return result of 30 calls.
* @throws InterruptedException exception
*/
@GetMapping("/ratelimit")
public String invokeInfo() throws InterruptedException {
StringBuffer builder = new StringBuffer();
CountDownLatch count = new CountDownLatch(30);
public String invokeInfo() {
StringBuilder builder = new StringBuilder();
AtomicInteger index = new AtomicInteger(0);
for (int i = 0; i < 30; i++) {
new Thread(() -> {
try {
ResponseEntity<String> entity = restTemplate.getForEntity(
"http://QuickstartCalleeService/quickstart/callee/info", String.class);
builder.append(entity.getBody() + "\n");
try {
ResponseEntity<String> entity = restTemplate.getForEntity(
"http://QuickstartCalleeService/quickstart/callee/info", String.class);
builder.append(entity.getBody() + "\n");
Thread.sleep(30);
}
catch (RestClientException e) {
if (e instanceof HttpClientErrorException.TooManyRequests) {
builder.append("TooManyRequests " + index.incrementAndGet() + "\n");
}
else {
throw e;
}
catch (InterruptedException e) {
throw new RuntimeException(e);
}
count.countDown();
}).start();
}
catch (RestClientException e) {
if (e instanceof HttpClientErrorException.TooManyRequests) {
builder.append("TooManyRequests " + index.incrementAndGet() + "\n");
}
else {
throw e;
}
}
}
count.await();
return builder.toString();
}

@ -50,3 +50,8 @@ management:
include:
- polaris-discovery
- polaris-circuit-breaker
logging:
file:
name: /sct-demo-logs/${spring.application.name}/root.log
level:
root: INFO

@ -57,3 +57,8 @@ spring:
- Path=/QuickstartCallerService/**
filters:
- StripPrefix=1
logging:
file:
name: /sct-demo-logs/${spring.application.name}/root.log
level:
root: INFO

@ -27,6 +27,11 @@
<artifactId>spring-cloud-starter-tencent-polaris-contract</artifactId>
</dependency>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-ratelimit</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>

@ -53,6 +53,7 @@ public class TsfContextConfigModifier implements PolarisConfigModifier {
tsfEventReporterConfig.setTsfNamespaceId(tsfCoreProperties.getTsfNamespaceId());
tsfEventReporterConfig.setServiceName(tsfCoreProperties.getServiceName());
tsfEventReporterConfig.setToken(consulProperties.getAclToken());
tsfEventReporterConfig.setApplicationId(tsfCoreProperties.getTsfApplicationId());
configuration.getGlobal().getEventReporter()
.setPluginConfig(DefaultPlugins.TSF_EVENT_REPORTER_TYPE, tsfEventReporterConfig);
}

@ -129,6 +129,12 @@ public class TsfCoreProperties {
@Value("${tsf_event_master_port:15200}")
private Integer eventMasterPort;
@Value("${tsf_ratelimit_master_ip:}")
private String ratelimitMasterIp;
@Value("${tsf_ratelimit_master_port:7000}")
private Integer ratelimitMasterPort;
public String getAppId() {
return appId;
}
@ -270,6 +276,22 @@ public class TsfCoreProperties {
this.eventMasterPort = eventMasterPort;
}
public String getRatelimitMasterIp() {
return ratelimitMasterIp;
}
public void setRatelimitMasterIp(String ratelimitMasterIp) {
this.ratelimitMasterIp = ratelimitMasterIp;
}
public Integer getRatelimitMasterPort() {
return ratelimitMasterPort;
}
public void setRatelimitMasterPort(Integer ratelimitMasterPort) {
this.ratelimitMasterPort = ratelimitMasterPort;
}
@Override
public String toString() {
return "TsfCoreProperties{" +
@ -289,6 +311,8 @@ public class TsfCoreProperties {
", scheme='" + scheme + '\'' +
", eventMasterIp='" + eventMasterIp + '\'' +
", eventMasterPort=" + eventMasterPort +
", ratelimitMasterIp='" + ratelimitMasterIp + '\'' +
", ratelimitMasterPort=" + ratelimitMasterPort +
'}';
}
}

Loading…
Cancel
Save