Skip to content

Commit

Permalink
Merge pull request #1697 from hanbingleixue/xds-flowcontrol-common
Browse files Browse the repository at this point in the history
 Add the common module with XDS Retry functions
  • Loading branch information
Sherlockhan authored Dec 26, 2024
2 parents 9575185 + ad8d02c commit c66c14a
Show file tree
Hide file tree
Showing 37 changed files with 956 additions and 177 deletions.
2 changes: 0 additions & 2 deletions .github/workflows/backend_integration_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,5 +102,3 @@ jobs:
uses: ./.github/actions/scenarios/backend/config
- name: start hot plugging test
uses: ./.github/actions/scenarios/backend/hot-plugging


Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@

package io.sermant.core.ext;

import com.sun.org.apache.bcel.internal.util.ClassLoader;

import io.sermant.core.classloader.FrameworkClassLoader;
import io.sermant.core.common.CommonConstant;
import io.sermant.core.common.LoggerFactory;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@
import io.sermant.flowcontrol.common.core.ResolverManager;
import io.sermant.flowcontrol.common.core.match.MatchManager;
import io.sermant.flowcontrol.common.core.resolver.AbstractResolver;
import io.sermant.flowcontrol.common.core.rule.AbstractRule;
import io.sermant.flowcontrol.common.entity.FlowControlScenario;
import io.sermant.flowcontrol.common.entity.RequestEntity;
import io.sermant.flowcontrol.common.util.StringUtils;

import java.util.Collections;
import java.util.List;
Expand All @@ -39,7 +40,7 @@
* @author zhouss
* @since 2022-01-22
*/
public abstract class AbstractRequestHandler<H, R extends AbstractRule> {
public abstract class AbstractRequestHandler<H, R> {
/**
* Handler cache
*/
Expand Down Expand Up @@ -70,10 +71,21 @@ public List<H> getHandlers(RequestEntity request) {
return createOrGetHandlers(businessNames);
}

/**
* gets the specified request handler
*
* @param flowControlScenario matched scenario information
* @return handler
*/
public List<H> getXdsHandlers(FlowControlScenario flowControlScenario) {
Optional<H> handlerOptions = createHandler(flowControlScenario, StringUtils.EMPTY);
return handlerOptions.map(Collections::singletonList).orElse(Collections.emptyList());
}

/**
* create handler
*
* @param businessNames matched service name
* @param businessNames matching service scenarios
* @return handler
*/
public List<H> createOrGetHandlers(Set<String> businessNames) {
Expand All @@ -90,7 +102,7 @@ private Optional<H> create(String businessName) {
if (rule == null) {
return Optional.empty();
}
return createProcessor(businessName, rule);
return createHandler(businessName, rule);
}

/**
Expand All @@ -100,7 +112,18 @@ private Optional<H> create(String businessName) {
* @param rule matching resolution rules
* @return handler
*/
protected abstract Optional<H> createProcessor(String businessName, R rule);
protected abstract Optional<H> createHandler(String businessName, R rule);

/**
* create handler
*
* @param flowControlScenario matched business information
* @param businessName service scenario name
* @return handler
*/
public Optional<H> createHandler(FlowControlScenario flowControlScenario, String businessName) {
return Optional.empty();
}

/**
* get configuration key
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,18 @@ public boolean needRetry(Set<String> statusList, Object result) {
* @return response status code
* @throws UnsupportedOperationException unsupported operation
*/
protected Optional<String> getCode(Object result) {
public Optional<String> getCode(Object result) {
throw new UnsupportedOperationException();
}

/**
* Get the name of the response header in the response information
*
* @param result interface response result
* @return response header names
* @throws UnsupportedOperationException unsupported operation
*/
public Optional<Set<String>> getHeaderNames(Object result) {
throw new UnsupportedOperationException();
}

Expand All @@ -97,7 +108,7 @@ protected final Class<? extends Throwable>[] getRetryExceptions() {
final RetryFramework retryFramework = retryType();
final FlowControlConfig pluginConfig = PluginConfigManager.getPluginConfig(FlowControlConfig.class);
String[] retryExceptions;
if (retryFramework == RetryFramework.SPRING_CLOUD) {
if (retryFramework == RetryFramework.SPRING_CLOUD || retryFramework == RetryFramework.SPRING) {
retryExceptions = pluginConfig.getSpringRetryExceptions();
} else if (retryFramework == RetryFramework.ALIBABA_DUBBO) {
retryExceptions = pluginConfig.getAlibabaDubboRetryExceptions();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package io.sermant.flowcontrol.common.handler.retry;

import java.util.Optional;
import java.util.Set;

/**
Expand Down Expand Up @@ -49,6 +50,22 @@ public interface Retry {
*/
RetryFramework retryType();

/**
* get status code
*
* @param result interface response result
* @return response status code
*/
Optional<String> getCode(Object result);

/**
* get header
*
* @param result interface response result
* @return response header names
*/
Optional<Set<String>> getHeaderNames(Object result);

/**
* retryFrame
*
Expand All @@ -68,6 +85,11 @@ enum RetryFramework {
/**
* apache dubbo retry
*/
APACHE_DUBBO
APACHE_DUBBO,

/**
* Spring retry
*/
SPRING;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,19 @@

package io.sermant.flowcontrol.common.handler.retry;

import io.sermant.core.service.xds.entity.XdsRetryPolicy;
import io.sermant.flowcontrol.common.core.RuleUtils;
import io.sermant.flowcontrol.common.core.resolver.RetryResolver;
import io.sermant.flowcontrol.common.core.rule.RetryRule;
import io.sermant.flowcontrol.common.entity.FlowControlScenario;
import io.sermant.flowcontrol.common.entity.HttpRequestEntity;
import io.sermant.flowcontrol.common.handler.retry.policy.RetryOnSamePolicy;
import io.sermant.flowcontrol.common.handler.retry.policy.RetryOnUntriedPolicy;
import io.sermant.flowcontrol.common.handler.retry.policy.RetryPolicy;
import io.sermant.flowcontrol.common.util.StringUtils;
import io.sermant.flowcontrol.common.xds.handler.XdsHandler;

import java.util.List;
import java.util.Optional;

/**
* Retry context, used to manage retry policies based on different host framework types
Expand Down Expand Up @@ -87,7 +92,7 @@ public boolean isPolicyNeedRetry() {
if (retryPolicy == null) {
return false;
}
return retryPolicy.isRetry() && retryPolicy.needRetry();
return retryPolicy.isRetry() && retryPolicy.isReachedRetryThreshold();
}

/**
Expand All @@ -104,12 +109,12 @@ public RetryPolicy getRetryPolicy() {
*
* @param serviceInstance service instance
*/
public void updateServiceInstance(Object serviceInstance) {
public void updateRetriedServiceInstance(Object serviceInstance) {
final RetryPolicy retryPolicy = getRetryPolicy();
if (retryPolicy == null) {
return;
}
retryPolicy.update(serviceInstance);
retryPolicy.updateRetriedInstance(serviceInstance);
retryPolicy.retryMark();
}

Expand All @@ -119,7 +124,7 @@ public void updateServiceInstance(Object serviceInstance) {
* @param retryRule retry rule
*/
public void buildRetryPolicy(RetryRule retryRule) {
policyThreadLocal.set(new RetryOnSamePolicy(retryRule.getRetryOnSame()));
policyThreadLocal.set(new RetryOnUntriedPolicy(retryRule.getRetryOnSame()));
}

/**
Expand All @@ -134,4 +139,23 @@ public void buildRetryPolicy(HttpRequestEntity requestEntity) {
RetryContext.INSTANCE.buildRetryPolicy(rule.get(0));
}
}

/**
* build test strategy
*
* @param scenario scenario information
*/
public void buildXdsRetryPolicy(FlowControlScenario scenario) {
if (StringUtils.isEmpty(scenario.getServiceName())
|| StringUtils.isEmpty(scenario.getRouteName())) {
return;
}
Optional<XdsRetryPolicy> retryPolicyOptional = XdsHandler.INSTANCE
.getRetryPolicy(scenario.getServiceName(), scenario.getRouteName());
if (!retryPolicyOptional.isPresent()) {
return;
}
XdsRetryPolicy retryPolicy = retryPolicyOptional.get();
policyThreadLocal.set(new RetryOnUntriedPolicy((int) retryPolicy.getMaxAttempts()));
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright (C) 2024-2024 Sermant Authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 io.sermant.flowcontrol.common.handler.retry.policy;

import java.util.HashSet;
import java.util.Set;

/**
* Retry on the Untried instance, regardless of thread safety, only on thread variables
*
* @author zhp
* @since 2024-11-28
*/
public class RetryOnUntriedPolicy implements RetryPolicy {
private final int attempts;

private final Set<Object> retriedInstance;

private int hasTriedCount;

private boolean isRetry;

private boolean isFirstRequest = true;

/**
* retry constructor
*
* @param attempts Maximum Retry Count
*/
public RetryOnUntriedPolicy(int attempts) {
this.attempts = attempts;
retriedInstance = new HashSet<>();
}

@Override
public boolean isReachedRetryThreshold() {
return hasTriedCount < attempts;
}

@Override
public void retryMark() {
if (!isFirstRequest) {
this.hasTriedCount++;
}
this.isRetry = true;
isFirstRequest = false;
}

@Override
public boolean isRetry() {
return isRetry;
}

@Override
public Set<Object> getAllRetriedInstance() {
return retriedInstance;
}

@Override
public void updateRetriedInstance(Object instance) {
if (!this.retriedInstance.contains(instance)) {
this.retriedInstance.add(instance);
}
}
}
Loading

0 comments on commit c66c14a

Please sign in to comment.