You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by li...@apache.org on 2021/01/11 11:14:36 UTC
[servicecomb-java-chassis] 03/07: [SCB-2116]add provider
implementation and refactor some api
This is an automated email from the ASF dual-hosted git repository.
liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git
commit 6de804859c4dd91c9351a71e6bbed0b2aa3f413b
Author: liubao <bi...@qq.com>
AuthorDate: Mon Jan 4 09:16:57 2021 +0800
[SCB-2116]add provider implementation and refactor some api
---
.../foundation/common/utils/BeanUtils.java | 8 ++
.../apache/servicecomb/governance/GovManager.java | 87 --------------
...Handler.java => AbstractGovernanceHandler.java} | 17 ++-
.../governance/handler/BulkheadHandler.java | 16 +--
.../governance/handler/CircuitBreakerHandler.java | 23 +---
.../servicecomb/governance/handler/GovHandler.java | 28 -----
.../governance/handler/RateLimitingHandler.java | 21 +---
.../governance/handler/RetryHandler.java | 21 +---
.../servicecomb/governance/FlowControlTest.java | 13 +-
.../governance/GovernancePropertiesTest.java | 29 ++---
handlers/handler-governance/README.md | 3 +
handlers/handler-governance/pom.xml | 65 ++++++++++
.../governance/ProviderGovernanceHandler.java | 132 +++++++++++++++++++++
....servicecomb.registry.discovery.DiscoveryFilter | 17 +++
.../src/main/resources/config/cse.handler.xml | 21 ++++
handlers/pom.xml | 1 +
16 files changed, 301 insertions(+), 201 deletions(-)
diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/BeanUtils.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/BeanUtils.java
index fc7606e..4e58615 100644
--- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/BeanUtils.java
+++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/BeanUtils.java
@@ -141,6 +141,14 @@ public final class BeanUtils {
return context.getBeansOfType(type);
}
+ public static <T> T getBean(Class<T> type) {
+ if (context == null) {
+ // for some test case
+ return null;
+ }
+ return context.getBean(type);
+ }
+
/**
* Get the implemented class of the given instance
* @param bean the instance to get implemented class from
diff --git a/governance/src/main/java/org/apache/servicecomb/governance/GovManager.java b/governance/src/main/java/org/apache/servicecomb/governance/GovManager.java
deleted file mode 100644
index e3752e3..0000000
--- a/governance/src/main/java/org/apache/servicecomb/governance/GovManager.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.servicecomb.governance;
-
-import java.util.List;
-import java.util.Map;
-
-import org.apache.servicecomb.governance.handler.GovHandler;
-import org.apache.servicecomb.governance.handler.HandlerType;
-import org.apache.servicecomb.governance.handler.ext.ClientRecoverPolicy;
-import org.apache.servicecomb.governance.handler.ext.ServerRecoverPolicy;
-import org.apache.servicecomb.governance.policy.Policy;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-import io.github.resilience4j.decorators.Decorators;
-import io.github.resilience4j.decorators.Decorators.DecorateCheckedSupplier;
-import io.vavr.CheckedFunction0;
-import io.vavr.control.Try;
-
-@Component
-public class GovManager {
-
- @Autowired
- Map<String, GovHandler> handlers;
-
- @Autowired(required = false)
- ServerRecoverPolicy<Object> serverRecoverPolicy;
-
- @Autowired(required = false)
- ClientRecoverPolicy<Object> clientRecoverPolicy;
-
- public Object processServer(List<Policy> policies, CheckedFunction0<Object> supplier) {
- DecorateCheckedSupplier<Object> ds = Decorators.ofCheckedSupplier(supplier);
- for (Policy policy : policies) {
- if (handlers.get(policy.handler()) == null ||
- handlers.get(policy.handler()).type() == HandlerType.CLIENT) {
- continue;
- }
- ds = handlers.get(policy.handler()).process(ds, policy);
- }
-
- Try<Object> of = Try.of(ds.decorate());
- return of
- .recover(throwable -> {
- if (serverRecoverPolicy == null) {
- throw (RuntimeException) throwable;
- } else {
- return serverRecoverPolicy.apply(throwable);
- }
- }).get();
- }
-
- public Object processClient(List<Policy> policies, CheckedFunction0<Object> supplier) {
- DecorateCheckedSupplier<Object> ds = Decorators.ofCheckedSupplier(supplier);
- for (Policy policy : policies) {
- if (handlers.get(policy.handler()) == null ||
- handlers.get(policy.handler()).type() == HandlerType.SERVER) {
- continue;
- }
- ds = handlers.get(policy.handler()).process(ds, policy);
- }
- Try<Object> of = Try.of(ds.decorate());
- return of
- .recover(throwable -> {
- if (clientRecoverPolicy == null) {
- throw (RuntimeException) throwable;
- } else {
- return clientRecoverPolicy.apply(throwable);
- }
- }).get();
- }
-}
diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/AbstractGovHandler.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/AbstractGovernanceHandler.java
similarity index 80%
rename from governance/src/main/java/org/apache/servicecomb/governance/handler/AbstractGovHandler.java
rename to governance/src/main/java/org/apache/servicecomb/governance/handler/AbstractGovernanceHandler.java
index a6f008e..1cb55d1 100644
--- a/governance/src/main/java/org/apache/servicecomb/governance/handler/AbstractGovHandler.java
+++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/AbstractGovernanceHandler.java
@@ -19,28 +19,33 @@ package org.apache.servicecomb.governance.handler;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
-import java.util.function.Function;
-import com.google.common.eventbus.Subscribe;
import org.apache.servicecomb.governance.event.ConfigurationChangedEvent;
import org.apache.servicecomb.governance.event.EventManager;
-public abstract class AbstractGovHandler<PROCESSOR> implements GovHandler {
+import com.google.common.eventbus.Subscribe;
+
+public abstract class AbstractGovernanceHandler<PROCESSOR, POLICY> {
private Map<String, PROCESSOR> map = new ConcurrentHashMap<>();
- protected AbstractGovHandler() {
+ protected AbstractGovernanceHandler() {
EventManager.register(this);
}
- protected <R> PROCESSOR getActuator(String key, R policy, Function<R, PROCESSOR> func) {
+ public <R> PROCESSOR getActuator(POLICY policy) {
+ String key = createKey(policy);
PROCESSOR processor = map.get(key);
if (processor == null) {
- processor = func.apply(policy);
+ processor = createProcessor(policy);
map.put(key, processor);
}
return processor;
}
+ abstract protected String createKey(POLICY policy);
+
+ abstract protected PROCESSOR createProcessor(POLICY policy);
+
@Subscribe
public void onDynamicConfigurationListener(ConfigurationChangedEvent event) {
event.getChangedConfigurations().forEach(v -> map.remove(v));
diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/BulkheadHandler.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/BulkheadHandler.java
index df99d93..c5b2497 100644
--- a/governance/src/main/java/org/apache/servicecomb/governance/handler/BulkheadHandler.java
+++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/BulkheadHandler.java
@@ -19,32 +19,28 @@ package org.apache.servicecomb.governance.handler;
import java.time.Duration;
+import org.apache.servicecomb.governance.policy.BulkheadPolicy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
-import org.apache.servicecomb.governance.policy.BulkheadPolicy;
-import org.apache.servicecomb.governance.policy.Policy;
-
import io.github.resilience4j.bulkhead.Bulkhead;
import io.github.resilience4j.bulkhead.BulkheadConfig;
import io.github.resilience4j.bulkhead.BulkheadRegistry;
import io.github.resilience4j.decorators.Decorators.DecorateCheckedSupplier;
@Component("BulkheadHandler")
-public class BulkheadHandler extends AbstractGovHandler<Bulkhead> {
+public class BulkheadHandler extends AbstractGovernanceHandler<Bulkhead, BulkheadPolicy> {
private static final Logger LOGGER = LoggerFactory.getLogger(BulkheadHandler.class);
@Override
- public <RESULT> DecorateCheckedSupplier<RESULT> process(DecorateCheckedSupplier<RESULT> supplier, Policy policy) {
- Bulkhead bulkhead = getActuator("servicecomb.bulkhead." + policy.name(), (BulkheadPolicy) policy,
- this::getBulkhead);
- return supplier.withBulkhead(bulkhead);
+ protected String createKey(BulkheadPolicy policy) {
+ return "servicecomb.bulkhead." + policy.name();
}
@Override
- public HandlerType type() {
- return HandlerType.SERVER;
+ protected Bulkhead createProcessor(BulkheadPolicy policy) {
+ return getBulkhead(policy);
}
private Bulkhead getBulkhead(BulkheadPolicy policy) {
diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/CircuitBreakerHandler.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/CircuitBreakerHandler.java
index 91dfdf9..d041edc 100644
--- a/governance/src/main/java/org/apache/servicecomb/governance/handler/CircuitBreakerHandler.java
+++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/CircuitBreakerHandler.java
@@ -18,40 +18,29 @@ package org.apache.servicecomb.governance.handler;
import java.time.Duration;
+import org.apache.servicecomb.governance.policy.CircuitBreakerPolicy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
-import org.apache.servicecomb.governance.policy.CircuitBreakerPolicy;
-import org.apache.servicecomb.governance.policy.Policy;
-
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
-import io.github.resilience4j.decorators.Decorators.DecorateCheckedSupplier;
@Component("CircuitBreakerHandler")
-public class CircuitBreakerHandler extends AbstractGovHandler<CircuitBreaker> {
+public class CircuitBreakerHandler extends AbstractGovernanceHandler<CircuitBreaker, CircuitBreakerPolicy> {
private static final Logger LOGGER = LoggerFactory.getLogger(CircuitBreakerHandler.class);
@Override
- public <RESULT> DecorateCheckedSupplier<RESULT> process(DecorateCheckedSupplier<RESULT> supplier, Policy policy) {
- CircuitBreaker circuitBreaker = getActuator("servicecomb.circuitBreaker." + policy.name(),
- (CircuitBreakerPolicy) policy, this::getCircuitBreaker);
- return supplier.withCircuitBreaker(circuitBreaker);
+ protected String createKey(CircuitBreakerPolicy policy) {
+ return "servicecomb.circuitBreaker." + policy.name();
}
@Override
- public HandlerType type() {
- return HandlerType.SERVER;
+ protected CircuitBreaker createProcessor(CircuitBreakerPolicy policy) {
+ return getCircuitBreaker(policy);
}
- /**
- * todo: recordExceptions
- *
- * @param policy
- * @return
- */
private CircuitBreaker getCircuitBreaker(CircuitBreakerPolicy policy) {
LOGGER.info("applying new policy: {}", policy.toString());
diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/GovHandler.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/GovHandler.java
deleted file mode 100644
index 81a9611..0000000
--- a/governance/src/main/java/org/apache/servicecomb/governance/handler/GovHandler.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.servicecomb.governance.handler;
-
-import org.apache.servicecomb.governance.policy.Policy;
-
-import io.github.resilience4j.decorators.Decorators.DecorateCheckedSupplier;
-
-public interface GovHandler {
-
- <RESULT> DecorateCheckedSupplier<RESULT> process(DecorateCheckedSupplier<RESULT> supplier, Policy policy);
-
- HandlerType type();
-}
diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/RateLimitingHandler.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/RateLimitingHandler.java
index 82a271a..dcdb5d8 100644
--- a/governance/src/main/java/org/apache/servicecomb/governance/handler/RateLimitingHandler.java
+++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/RateLimitingHandler.java
@@ -18,38 +18,29 @@ package org.apache.servicecomb.governance.handler;
import java.time.Duration;
+import org.apache.servicecomb.governance.policy.RateLimitingPolicy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
-import org.apache.servicecomb.governance.policy.Policy;
-import org.apache.servicecomb.governance.policy.RateLimitingPolicy;
-
-import io.github.resilience4j.decorators.Decorators.DecorateCheckedSupplier;
import io.github.resilience4j.ratelimiter.RateLimiter;
import io.github.resilience4j.ratelimiter.RateLimiterConfig;
import io.github.resilience4j.ratelimiter.RateLimiterRegistry;
@Component("RateLimitingHandler")
-public class RateLimitingHandler extends AbstractGovHandler<RateLimiter> {
+public class RateLimitingHandler extends AbstractGovernanceHandler<RateLimiter, RateLimitingPolicy> {
private static final Logger LOGGER = LoggerFactory.getLogger(RateLimitingHandler.class);
@Override
- public <RESULT> DecorateCheckedSupplier<RESULT> process(DecorateCheckedSupplier<RESULT> supplier, Policy policy) {
- RateLimiter rateLimiter = getActuator("servicecomb.rateLimiting." + policy.name(), (RateLimitingPolicy) policy,
- this::getRateLimiter);
- return supplier.withRateLimiter(rateLimiter);
+ protected String createKey(RateLimitingPolicy policy) {
+ return "servicecomb.rateLimiting." + policy.name();
}
@Override
- public HandlerType type() {
- return HandlerType.SERVER;
+ protected RateLimiter createProcessor(RateLimitingPolicy policy) {
+ return getRateLimiter(policy);
}
- /**
- * @param policy
- * @return
- */
private RateLimiter getRateLimiter(RateLimitingPolicy policy) {
LOGGER.info("applying new policy: {}", policy.toString());
diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/RetryHandler.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/RetryHandler.java
index 86b902d..068bb55 100644
--- a/governance/src/main/java/org/apache/servicecomb/governance/handler/RetryHandler.java
+++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/RetryHandler.java
@@ -22,42 +22,33 @@ import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
-import org.apache.servicecomb.governance.policy.Policy;
+import org.apache.servicecomb.governance.handler.ext.RetryExtension;
import org.apache.servicecomb.governance.policy.RetryPolicy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
-import org.apache.servicecomb.governance.handler.ext.RetryExtension;
-
-import io.github.resilience4j.decorators.Decorators.DecorateCheckedSupplier;
import io.github.resilience4j.retry.Retry;
import io.github.resilience4j.retry.RetryConfig;
import io.github.resilience4j.retry.RetryRegistry;
@Component("RetryHandler")
-public class RetryHandler extends AbstractGovHandler<Retry> {
+public class RetryHandler extends AbstractGovernanceHandler<Retry, RetryPolicy> {
private static final Logger LOGGER = LoggerFactory.getLogger(RetryHandler.class);
@Autowired
private RetryExtension retryExtension;
- /**
- * @param supplier
- * @param policy
- * @return
- */
@Override
- public <RESULT> DecorateCheckedSupplier<RESULT> process(DecorateCheckedSupplier<RESULT> supplier, Policy policy) {
- Retry retry = getActuator("servicecomb.retry." + policy.name(), (RetryPolicy) policy, this::getRetry);
- return supplier.withRetry(retry);
+ protected String createKey(RetryPolicy policy) {
+ return "servicecomb.retry." + policy.name();
}
@Override
- public HandlerType type() {
- return HandlerType.CLIENT;
+ protected Retry createProcessor(RetryPolicy policy) {
+ return getRetry(policy);
}
private Retry getRetry(RetryPolicy retryPolicy) {
diff --git a/governance/src/test/java/org/apache/servicecomb/governance/FlowControlTest.java b/governance/src/test/java/org/apache/servicecomb/governance/FlowControlTest.java
index 8aeddba..e16dafa 100644
--- a/governance/src/test/java/org/apache/servicecomb/governance/FlowControlTest.java
+++ b/governance/src/test/java/org/apache/servicecomb/governance/FlowControlTest.java
@@ -23,7 +23,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.servicecomb.governance.handler.RateLimitingHandler;
import org.apache.servicecomb.governance.marker.GovHttpRequest;
-import org.apache.servicecomb.governance.policy.Policy;
+import org.apache.servicecomb.governance.policy.RateLimitingPolicy;
import org.apache.servicecomb.governance.properties.RateLimitProperties;
import org.junit.Assert;
import org.junit.Test;
@@ -35,6 +35,7 @@ import org.springframework.test.context.junit4.SpringRunner;
import io.github.resilience4j.decorators.Decorators;
import io.github.resilience4j.decorators.Decorators.DecorateCheckedSupplier;
+import io.github.resilience4j.ratelimiter.RateLimiter;
import io.github.resilience4j.ratelimiter.RequestNotPermitted;
@RunWith(SpringRunner.class)
@@ -57,11 +58,12 @@ public class FlowControlTest {
GovHttpRequest request = new GovHttpRequest("testService", "1.0");
request.setUri("/hello");
- Policy policy = matchersManager.match(request, rateLimitProperties.getParsedEntity());
+ RateLimitingPolicy policy = matchersManager.match(request, rateLimitProperties.getParsedEntity());
Assert.assertNotNull(policy);
- DecorateCheckedSupplier<Object> dcs = rateLimitingHandler.process(ds, policy);
+ RateLimiter rateLimiter = rateLimitingHandler.getActuator(policy);
+ ds.withRateLimiter(rateLimiter);
- Assert.assertEquals("test", dcs.get());
+ Assert.assertEquals("test", ds.get());
// flow control
CountDownLatch cd = new CountDownLatch(10);
@@ -71,8 +73,7 @@ public class FlowControlTest {
new Thread() {
public void run() {
try {
- DecorateCheckedSupplier<Object> dcs = rateLimitingHandler.process(ds, policy);
- Object result = dcs.get();
+ Object result = ds.get();
if (!"test".equals(result)) {
notExpected.set(true);
}
diff --git a/governance/src/test/java/org/apache/servicecomb/governance/GovernancePropertiesTest.java b/governance/src/test/java/org/apache/servicecomb/governance/GovernancePropertiesTest.java
index 560bf05..971a09d 100644
--- a/governance/src/test/java/org/apache/servicecomb/governance/GovernancePropertiesTest.java
+++ b/governance/src/test/java/org/apache/servicecomb/governance/GovernancePropertiesTest.java
@@ -23,19 +23,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.ConfigFileApplicationContextInitializer;
-import org.springframework.core.env.ConfigurableEnvironment;
-import org.springframework.core.env.EnumerablePropertySource;
-import org.springframework.core.env.Environment;
-import org.springframework.test.context.ContextConfiguration;
-import org.springframework.test.context.junit4.SpringRunner;
-
import org.apache.servicecomb.governance.event.ConfigurationChangedEvent;
import org.apache.servicecomb.governance.event.EventManager;
import org.apache.servicecomb.governance.marker.Matcher;
@@ -51,6 +38,18 @@ import org.apache.servicecomb.governance.properties.GovernanceProperties;
import org.apache.servicecomb.governance.properties.MatchProperties;
import org.apache.servicecomb.governance.properties.RateLimitProperties;
import org.apache.servicecomb.governance.properties.RetryProperties;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.ConfigFileApplicationContextInitializer;
+import org.springframework.core.env.ConfigurableEnvironment;
+import org.springframework.core.env.EnumerablePropertySource;
+import org.springframework.core.env.Environment;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@ContextConfiguration(locations = "classpath:META-INF/spring/*.xml", initializers = ConfigFileApplicationContextInitializer.class)
@@ -79,10 +78,6 @@ public class GovernancePropertiesTest {
private Map<String, Object> dynamicValues = new HashMap<>();
- public GovernancePropertiesTest() {
- System.out.print(1);
- }
-
@Before
public void setUp() {
ConfigurableEnvironment configurableEnvironment = (ConfigurableEnvironment) environment;
diff --git a/handlers/handler-governance/README.md b/handlers/handler-governance/README.md
new file mode 100644
index 0000000..3a9db2f
--- /dev/null
+++ b/handlers/handler-governance/README.md
@@ -0,0 +1,3 @@
+Enable governance features by handler.
+
+Governance can be enabled in any different process layer, enable it in handler is most portable way.
\ No newline at end of file
diff --git a/handlers/handler-governance/pom.xml b/handlers/handler-governance/pom.xml
new file mode 100644
index 0000000..26aa4c6
--- /dev/null
+++ b/handlers/handler-governance/pom.xml
@@ -0,0 +1,65 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one or more
+ ~ contributor license agreements. See the NOTICE file distributed with
+ ~ this work for additional information regarding copyright ownership.
+ ~ The ASF licenses this file to You 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.
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.servicecomb</groupId>
+ <artifactId>handlers</artifactId>
+ <version>2.1.5-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>handler-governance</artifactId>
+ <name>Java Chassis::Handlers::Governance</name>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.servicecomb</groupId>
+ <artifactId>java-chassis-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.servicecomb</groupId>
+ <artifactId>servicecomb-governance</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.servicecomb</groupId>
+ <artifactId>registry-local</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.servicecomb</groupId>
+ <artifactId>foundation-test-scaffolding</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+</project>
diff --git a/handlers/handler-governance/src/main/java/org/apache/servicecomb/handler/governance/ProviderGovernanceHandler.java b/handlers/handler-governance/src/main/java/org/apache/servicecomb/handler/governance/ProviderGovernanceHandler.java
new file mode 100644
index 0000000..06d0c50
--- /dev/null
+++ b/handlers/handler-governance/src/main/java/org/apache/servicecomb/handler/governance/ProviderGovernanceHandler.java
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.servicecomb.handler.governance;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionStage;
+import java.util.function.Supplier;
+
+import org.apache.servicecomb.core.Handler;
+import org.apache.servicecomb.core.Invocation;
+import org.apache.servicecomb.foundation.common.utils.BeanUtils;
+import org.apache.servicecomb.governance.MatchersManager;
+import org.apache.servicecomb.governance.handler.BulkheadHandler;
+import org.apache.servicecomb.governance.handler.CircuitBreakerHandler;
+import org.apache.servicecomb.governance.handler.RateLimitingHandler;
+import org.apache.servicecomb.governance.marker.GovHttpRequest;
+import org.apache.servicecomb.governance.policy.BulkheadPolicy;
+import org.apache.servicecomb.governance.policy.CircuitBreakerPolicy;
+import org.apache.servicecomb.governance.policy.RateLimitingPolicy;
+import org.apache.servicecomb.governance.properties.BulkheadProperties;
+import org.apache.servicecomb.governance.properties.CircuitBreakerProperties;
+import org.apache.servicecomb.governance.properties.RateLimitProperties;
+import org.apache.servicecomb.registry.RegistrationManager;
+import org.apache.servicecomb.swagger.invocation.AsyncResponse;
+import org.apache.servicecomb.swagger.invocation.Response;
+import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData;
+import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.github.resilience4j.bulkhead.BulkheadFullException;
+import io.github.resilience4j.circuitbreaker.CallNotPermittedException;
+import io.github.resilience4j.decorators.Decorators;
+import io.github.resilience4j.decorators.Decorators.DecorateCompletionStage;
+import io.github.resilience4j.ratelimiter.RequestNotPermitted;
+
+public class ProviderGovernanceHandler implements Handler {
+ private static final Logger LOGGER = LoggerFactory.getLogger(ProviderGovernanceHandler.class);
+
+ private MatchersManager matchersManager = BeanUtils.getBean(MatchersManager.class);
+
+ private RateLimitingHandler rateLimitingHandler = BeanUtils.getBean(RateLimitingHandler.class);
+
+ private RateLimitProperties rateLimitProperties = BeanUtils.getBean(RateLimitProperties.class);
+
+ private CircuitBreakerHandler circuitBreakerHandler = BeanUtils.getBean(CircuitBreakerHandler.class);
+
+ private CircuitBreakerProperties circuitBreakerProperties = BeanUtils.getBean(CircuitBreakerProperties.class);
+
+ private BulkheadHandler bulkheadHandler = BeanUtils.getBean(BulkheadHandler.class);
+
+ private BulkheadProperties bulkheadProperties = BeanUtils.getBean(BulkheadProperties.class);
+
+ @Override
+ public void handle(Invocation invocation, AsyncResponse asyncResp) throws Exception {
+
+ Supplier<CompletionStage<Response>> next = createBusinessCompletionStageSupplier(invocation);
+ DecorateCompletionStage<Response> dcs = Decorators.ofCompletionStage(next);
+ GovHttpRequest request = createGovHttpRequest(invocation);
+
+ RateLimitingPolicy rateLimitingPolicy = matchersManager.match(request, rateLimitProperties.getParsedEntity());
+ dcs.withRateLimiter(rateLimitingHandler.getActuator(rateLimitingPolicy));
+ CircuitBreakerPolicy circuitBreakerPolicy = matchersManager
+ .match(request, circuitBreakerProperties.getParsedEntity());
+ dcs.withCircuitBreaker(circuitBreakerHandler.getActuator(circuitBreakerPolicy));
+ BulkheadPolicy bulkheadPolicy = matchersManager.match(request, bulkheadProperties.getParsedEntity());
+ dcs.withBulkhead(bulkheadHandler.getActuator(bulkheadPolicy));
+
+ dcs.get().whenComplete((r, e) -> {
+ if (e == null) {
+ asyncResp.complete(r);
+ return;
+ }
+
+ if (e instanceof RequestNotPermitted) {
+ asyncResp.complete(
+ Response.failResp(new InvocationException(429, "rate limited.", new CommonExceptionData("rate limited."))));
+ LOGGER.warn("the request is rate limit by policy : {}", e.getMessage());
+ } else if (e instanceof CallNotPermittedException) {
+ asyncResp.complete(
+ Response.failResp(new InvocationException(429, "circuitBreaker is open.",
+ new CommonExceptionData("circuitBreaker is open."))));
+ LOGGER.warn("circuitBreaker is open by policy : {}", e.getMessage());
+ } else if (e instanceof BulkheadFullException) {
+ asyncResp.complete(
+ Response.failResp(new InvocationException(429, "bulkhead is full and does not permit further calls.",
+ new CommonExceptionData("bulkhead is full and does not permit further calls."))));
+ LOGGER.warn("bulkhead is full and does not permit further calls by policy : {}", e.getMessage());
+ } else {
+ asyncResp.complete(Response.createProducerFail(e));
+ }
+ });
+ }
+
+ private Supplier<CompletionStage<Response>> createBusinessCompletionStageSupplier(Invocation invocation) {
+ return () -> {
+ CompletableFuture<Response> result = new CompletableFuture<>();
+ try {
+ invocation.next(response -> {
+ result.complete(response);
+ });
+ } catch (Exception e) {
+ result.completeExceptionally(e);
+ }
+ return result;
+ };
+ }
+
+ private GovHttpRequest createGovHttpRequest(Invocation invocation) {
+ GovHttpRequest request = new GovHttpRequest(RegistrationManager.INSTANCE.getMicroservice().getServiceName(),
+ RegistrationManager.INSTANCE.getMicroservice().getVersion());
+ request.setUri(invocation.getSchemaId() + "." + invocation.getOperationName());
+ request.setMethod(invocation.getOperationMeta().getHttpMethod());
+ request.setHeaders(invocation.getContext());
+ return request;
+ }
+}
diff --git a/handlers/handler-governance/src/main/resources/META-INF/services/org.apache.servicecomb.registry.discovery.DiscoveryFilter b/handlers/handler-governance/src/main/resources/META-INF/services/org.apache.servicecomb.registry.discovery.DiscoveryFilter
new file mode 100644
index 0000000..6222972
--- /dev/null
+++ b/handlers/handler-governance/src/main/resources/META-INF/services/org.apache.servicecomb.registry.discovery.DiscoveryFilter
@@ -0,0 +1,17 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
+
diff --git a/handlers/handler-governance/src/main/resources/config/cse.handler.xml b/handlers/handler-governance/src/main/resources/config/cse.handler.xml
new file mode 100644
index 0000000..f99f63d
--- /dev/null
+++ b/handlers/handler-governance/src/main/resources/config/cse.handler.xml
@@ -0,0 +1,21 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one or more
+ ~ contributor license agreements. See the NOTICE file distributed with
+ ~ this work for additional information regarding copyright ownership.
+ ~ The ASF licenses this file to You 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.
+ -->
+
+<config>
+ <handler id="governance-provider"
+ class="org.apache.servicecomb.handler.governance.ProviderGovernanceHandler"/>
+</config>
diff --git a/handlers/pom.xml b/handlers/pom.xml
index 2d5bb2f..c5cea16 100644
--- a/handlers/pom.xml
+++ b/handlers/pom.xml
@@ -39,6 +39,7 @@
<module>handler-fault-injection</module>
<module>handler-publickey-auth</module>
<module>handler-router</module>
+ <module>handler-governance</module>
</modules>
</project>