Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the common module with XDS Retry functions #1697

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading