This commit is contained in:
shuhongfan
2023-09-04 16:40:17 +08:00
commit cf5ac25c14
8267 changed files with 1305066 additions and 0 deletions

View File

@@ -0,0 +1,36 @@
# Sentinel gRPC Adapter
Sentinel gRPC Adapter provides client and server interceptor for gRPC services.
> Note that currently the interceptor only supports unary methods in gRPC.
## Client Interceptor
Example:
```java
public class ServiceClient {
private final ManagedChannel channel;
ServiceClient(String host, int port) {
this.channel = ManagedChannelBuilder.forAddress(host, port)
.intercept(new SentinelGrpcClientInterceptor()) // Add the client interceptor.
.build();
// Init your stub here.
}
}
```
## Server Interceptor
Example:
```java
import io.grpc.Server;
Server server = ServerBuilder.forPort(port)
.addService(new MyServiceImpl()) // Add your service.
.intercept(new SentinelGrpcServerInterceptor()) // Add the server interceptor.
.build();
```

View File

@@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>sentinel-adapter</artifactId>
<groupId>com.alibaba.csp</groupId>
<version>1.8.3</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>sentinel-grpc-adapter</artifactId>
<packaging>jar</packaging>
<properties>
<grpc.version>1.30.2</grpc.version>
</properties>
<dependencies>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty</artifactId>
<version>${grpc.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>${grpc.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
<version>${grpc.version}</version>
<scope>provided</scope>
</dependency>
<!-- workaround for compile in JDK 11 -->
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>${javax.annotation-api.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.5.0.Final</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.5.1</version>
<configuration>
<protocArtifact>com.google.protobuf:protoc:3.5.1-1:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}
</pluginArtifact>
</configuration>
<executions>
<execution>
<goals>
<goal>test-compile</goal>
<goal>test-compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,142 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* 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 com.alibaba.csp.sentinel.adapter.grpc;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import io.grpc.CallOptions;
import io.grpc.Channel;
import io.grpc.ClientCall;
import io.grpc.ClientInterceptor;
import io.grpc.ForwardingClientCall;
import io.grpc.ForwardingClientCallListener;
import io.grpc.Metadata;
import io.grpc.MethodDescriptor;
import io.grpc.Status;
import javax.annotation.Nullable;
import java.util.concurrent.atomic.AtomicReference;
/**
* <p>gRPC client interceptor for Sentinel. Currently it only works with unary methods.</p>
* <p>
* Example code:
* <pre>
* public class ServiceClient {
*
* private final ManagedChannel channel;
*
* ServiceClient(String host, int port) {
* this.channel = ManagedChannelBuilder.forAddress(host, port)
* .intercept(new SentinelGrpcClientInterceptor()) // Add the client interceptor.
* .build();
* // Init your stub here.
* }
*
* }
* </pre>
* <p>
* For server interceptor, see {@link SentinelGrpcServerInterceptor}.
*
* @author Eric Zhao
*/
public class SentinelGrpcClientInterceptor implements ClientInterceptor {
private static final Status FLOW_CONTROL_BLOCK = Status.UNAVAILABLE.withDescription(
"Flow control limit exceeded (client side)");
@Override
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> methodDescriptor,
CallOptions callOptions, Channel channel) {
String fullMethodName = methodDescriptor.getFullMethodName();
Entry entry = null;
try {
entry = SphU.asyncEntry(fullMethodName, EntryType.OUT);
final AtomicReference<Entry> atomicReferenceEntry = new AtomicReference<>(entry);
// Allow access, forward the call.
return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(
channel.newCall(methodDescriptor, callOptions)) {
@Override
public void start(Listener<RespT> responseListener, Metadata headers) {
super.start(new ForwardingClientCallListener.SimpleForwardingClientCallListener<RespT>(responseListener) {
@Override
public void onClose(Status status, Metadata trailers) {
Entry entry = atomicReferenceEntry.get();
if (entry != null) {
// Record the exception metrics.
if (!status.isOk()) {
Tracer.traceEntry(status.asRuntimeException(), entry);
}
entry.exit();
atomicReferenceEntry.set(null);
}
super.onClose(status, trailers);
}
}, headers);
}
/**
* Some Exceptions will only call cancel.
*/
@Override
public void cancel(@Nullable String message, @Nullable Throwable cause) {
Entry entry = atomicReferenceEntry.get();
// Some Exceptions will call onClose and cancel.
if (entry != null) {
// Record the exception metrics.
Tracer.traceEntry(cause, entry);
entry.exit();
atomicReferenceEntry.set(null);
}
super.cancel(message, cause);
}
};
} catch (BlockException e) {
// Flow control threshold exceeded, block the call.
return new ClientCall<ReqT, RespT>() {
@Override
public void start(Listener<RespT> responseListener, Metadata headers) {
responseListener.onClose(FLOW_CONTROL_BLOCK, new Metadata());
}
@Override
public void request(int numMessages) {
}
@Override
public void cancel(@Nullable String message, @Nullable Throwable cause) {
}
@Override
public void halfClose() {
}
@Override
public void sendMessage(ReqT message) {
}
};
} catch (RuntimeException e) {
// Catch the RuntimeException newCall throws, entry is guaranteed to exit.
if (entry != null) {
Tracer.traceEntry(e, entry);
entry.exit();
}
throw e;
}
}
}

View File

@@ -0,0 +1,109 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* 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 com.alibaba.csp.sentinel.adapter.grpc;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import io.grpc.ForwardingServerCall;
import io.grpc.ForwardingServerCallListener;
import io.grpc.Metadata;
import io.grpc.ServerCall;
import io.grpc.ServerCallHandler;
import io.grpc.ServerInterceptor;
import io.grpc.Status;
import io.grpc.StatusRuntimeException;
import java.util.concurrent.atomic.AtomicReference;
/**
* <p>gRPC server interceptor for Sentinel. Currently it only works with unary methods.</p>
* <p>
* Example code:
* <pre>
* Server server = ServerBuilder.forPort(port)
* .addService(new MyServiceImpl()) // Add your service.
* .intercept(new SentinelGrpcServerInterceptor()) // Add the server interceptor.
* .build();
* </pre>
* <p>
* For client interceptor, see {@link SentinelGrpcClientInterceptor}.
*
* @author Eric Zhao
*/
public class SentinelGrpcServerInterceptor implements ServerInterceptor {
private static final Status FLOW_CONTROL_BLOCK = Status.UNAVAILABLE.withDescription(
"Flow control limit exceeded (server side)");
private static final StatusRuntimeException STATUS_RUNTIME_EXCEPTION = new StatusRuntimeException(Status.CANCELLED);
@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
String fullMethodName = call.getMethodDescriptor().getFullMethodName();
// Remote address: serverCall.getAttributes().get(Grpc.TRANSPORT_ATTR_REMOTE_ADDR);
Entry entry = null;
try {
entry = SphU.asyncEntry(fullMethodName, EntryType.IN);
final AtomicReference<Entry> atomicReferenceEntry = new AtomicReference<>(entry);
// Allow access, forward the call.
return new ForwardingServerCallListener.SimpleForwardingServerCallListener<ReqT>(
next.startCall(
new ForwardingServerCall.SimpleForwardingServerCall<ReqT, RespT>(call) {
@Override
public void close(Status status, Metadata trailers) {
Entry entry = atomicReferenceEntry.get();
if (entry != null) {
// Record the exception metrics.
if (!status.isOk()) {
Tracer.traceEntry(status.asRuntimeException(), entry);
}
//entry exit when the call be closed
entry.exit();
}
super.close(status, trailers);
}
}, headers)) {
/**
* If call was canceled, onCancel will be called. and the close will not be called
* so the server is encouraged to abort processing to save resources by onCancel
* @see ServerCall.Listener#onCancel()
*/
@Override
public void onCancel() {
Entry entry = atomicReferenceEntry.get();
if (entry != null) {
Tracer.traceEntry(STATUS_RUNTIME_EXCEPTION, entry);
entry.exit();
atomicReferenceEntry.set(null);
}
super.onCancel();
}
};
} catch (BlockException e) {
call.close(FLOW_CONTROL_BLOCK, new Metadata());
return new ServerCall.Listener<ReqT>() {
};
} catch (RuntimeException e) {
// Catch the RuntimeException startCall throws, entry is guaranteed to exit.
if (entry != null) {
Tracer.traceEntry(e, entry);
entry.exit();
}
throw e;
}
}
}

View File

@@ -0,0 +1,68 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* 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 com.alibaba.csp.sentinel.adapter.grpc;
import com.alibaba.csp.sentinel.adapter.grpc.gen.FooRequest;
import com.alibaba.csp.sentinel.adapter.grpc.gen.FooResponse;
import com.alibaba.csp.sentinel.adapter.grpc.gen.FooServiceGrpc;
import io.grpc.ClientInterceptor;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import java.util.concurrent.TimeUnit;
/**
* A simple wrapped gRPC client for FooService.
*
* @author Eric Zhao
*/
final class FooServiceClient {
private final ManagedChannel channel;
private final FooServiceGrpc.FooServiceBlockingStub blockingStub;
FooServiceClient(String host, int port) {
this.channel = ManagedChannelBuilder.forAddress(host, port)
.usePlaintext()
.build();
this.blockingStub = FooServiceGrpc.newBlockingStub(this.channel);
}
FooServiceClient(String host, int port, ClientInterceptor interceptor) {
this.channel = ManagedChannelBuilder.forAddress(host, port)
.usePlaintext()
.intercept(interceptor)
.build();
this.blockingStub = FooServiceGrpc.newBlockingStub(this.channel);
}
FooResponse sayHello(FooRequest request) {
if (request == null) {
throw new IllegalArgumentException("Request cannot be null");
}
return blockingStub.sayHello(request);
}
FooResponse anotherHello(FooRequest request) {
if (request == null) {
throw new IllegalArgumentException("Request cannot be null");
}
return blockingStub.anotherHello(request);
}
void shutdown() throws InterruptedException {
channel.shutdown().awaitTermination(1, TimeUnit.SECONDS);
}
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* 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 com.alibaba.csp.sentinel.adapter.grpc;
import com.alibaba.csp.sentinel.adapter.grpc.gen.FooRequest;
import com.alibaba.csp.sentinel.adapter.grpc.gen.FooResponse;
import com.alibaba.csp.sentinel.adapter.grpc.gen.FooServiceGrpc;
import io.grpc.stub.StreamObserver;
/**
* Implementation of FooService defined in proto.
*/
class FooServiceImpl extends FooServiceGrpc.FooServiceImplBase {
@Override
public void sayHello(FooRequest request, StreamObserver<FooResponse> responseObserver) {
int id = request.getId();
switch (id) {
// Exception test
case -1:
responseObserver.onError(new IllegalAccessException("The id is error!"));
break;
// RT test
case -2:
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
responseObserver.onError(e);
break;
}
default:
String message = String.format("Hello %s! Your ID is %d.", request.getName(), id);
FooResponse response = FooResponse.newBuilder().setMessage(message).build();
responseObserver.onNext(response);
responseObserver.onCompleted();
break;
}
}
@Override
public void anotherHello(FooRequest request, StreamObserver<FooResponse> responseObserver) {
int id = request.getId();
switch (id) {
// Exception test
case -1:
responseObserver.onError(new IllegalAccessException("The id is error!"));
break;
// RT test
case -2:
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
responseObserver.onError(e);
break;
}
default:
String message = String.format("Good day, %s (%d)", request.getName(), id);
FooResponse response = FooResponse.newBuilder().setMessage(message).build();
responseObserver.onNext(response);
responseObserver.onCompleted();
break;
}
}
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* 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 com.alibaba.csp.sentinel.adapter.grpc;
import io.grpc.Server;
import io.grpc.ServerBuilder;
import java.io.IOException;
import java.util.concurrent.Executors;
class GrpcTestServer {
private Server server;
GrpcTestServer() {}
void start(int port, boolean shouldIntercept) throws IOException {
if (server != null) {
throw new IllegalStateException("Server already running!");
}
ServerBuilder<?> serverBuild = ServerBuilder.forPort(port)
.addService(new FooServiceImpl());
if (shouldIntercept) {
serverBuild.intercept(new SentinelGrpcServerInterceptor());
}
server = serverBuild.build();
server.start();
}
void stop() {
if (server != null) {
server.shutdown();
server = null;
}
}
}

View File

@@ -0,0 +1,109 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* 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 com.alibaba.csp.sentinel.adapter.grpc;
import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.adapter.grpc.gen.FooRequest;
import com.alibaba.csp.sentinel.adapter.grpc.gen.FooResponse;
import com.alibaba.csp.sentinel.node.ClusterNode;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot;
import io.grpc.StatusRuntimeException;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.Collections;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
/**
* Test cases for {@link SentinelGrpcClientInterceptor}.
*
* @author Eric Zhao
*/
public class SentinelGrpcClientInterceptorTest {
private final String fullMethodName = "com.alibaba.sentinel.examples.FooService/sayHello";
private final GrpcTestServer server = new GrpcTestServer();
private FooServiceClient client;
private void configureFlowRule(int count) {
FlowRule rule = new FlowRule()
.setCount(count)
.setGrade(RuleConstant.FLOW_GRADE_QPS)
.setResource(fullMethodName)
.setLimitApp("default")
.as(FlowRule.class);
FlowRuleManager.loadRules(Collections.singletonList(rule));
}
@Test
public void testGrpcClientInterceptor() throws Exception {
final int port = 19328;
server.start(port, false);
client = new FooServiceClient("localhost", port, new SentinelGrpcClientInterceptor());
configureFlowRule(Integer.MAX_VALUE);
assertTrue(sendRequest(FooRequest.newBuilder().setName("Sentinel").setId(666).build()));
ClusterNode clusterNode = ClusterBuilderSlot.getClusterNode(fullMethodName, EntryType.OUT);
assertNotNull(clusterNode);
assertEquals(1, clusterNode.totalPass());
// Not allowed to pass.
configureFlowRule(0);
// The second request will be blocked.
assertFalse(sendRequest(FooRequest.newBuilder().setName("Sentinel").setId(666).build()));
assertEquals(1, clusterNode.blockRequest());
configureFlowRule(Integer.MAX_VALUE);
assertFalse(sendRequest(FooRequest.newBuilder().setName("Sentinel").setId(-1).build()));
assertEquals(1, clusterNode.totalException());
configureFlowRule(Integer.MAX_VALUE);
assertTrue(sendRequest(FooRequest.newBuilder().setName("Sentinel").setId(-2).build()));
assertTrue(clusterNode.avgRt() >= 1000);
server.stop();
}
private boolean sendRequest(FooRequest request) {
try {
FooResponse response = client.sayHello(request);
System.out.println("Response: " + response);
return true;
} catch (StatusRuntimeException ex) {
System.out.println("Blocked, cause: " + ex.getMessage());
return false;
}
}
@Before
public void cleanUpBefore() {
FlowRuleManager.loadRules(null);
ClusterBuilderSlot.getClusterNodeMap().clear();
}
@After
public void cleanUpAfter() {
FlowRuleManager.loadRules(null);
ClusterBuilderSlot.getClusterNodeMap().clear();
}
}

View File

@@ -0,0 +1,109 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* 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 com.alibaba.csp.sentinel.adapter.grpc;
import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.adapter.grpc.gen.FooRequest;
import com.alibaba.csp.sentinel.adapter.grpc.gen.FooResponse;
import com.alibaba.csp.sentinel.node.ClusterNode;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot;
import io.grpc.StatusRuntimeException;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.Collections;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
/**
* Test cases for {@link SentinelGrpcServerInterceptor}.
*
* @author Eric Zhao
*/
public class SentinelGrpcServerInterceptorTest {
private final String resourceName = "com.alibaba.sentinel.examples.FooService/anotherHello";
private final GrpcTestServer server = new GrpcTestServer();
private FooServiceClient client;
private void configureFlowRule(int count) {
FlowRule rule = new FlowRule()
.setCount(count)
.setGrade(RuleConstant.FLOW_GRADE_QPS)
.setResource(resourceName)
.setLimitApp("default")
.as(FlowRule.class);
FlowRuleManager.loadRules(Collections.singletonList(rule));
}
@Test
public void testGrpcServerInterceptor() throws Exception {
final int port = 19329;
server.start(port, true);
client = new FooServiceClient("localhost", port);
configureFlowRule(Integer.MAX_VALUE);
assertTrue(sendRequest(FooRequest.newBuilder().setName("Sentinel").setId(666).build()));
ClusterNode clusterNode = ClusterBuilderSlot.getClusterNode(resourceName, EntryType.IN);
assertNotNull(clusterNode);
assertEquals(1, clusterNode.totalPass());
// Not allowed to pass.
configureFlowRule(0);
// The second request will be blocked.
assertFalse(sendRequest(FooRequest.newBuilder().setName("Sentinel").setId(666).build()));
assertEquals(1, clusterNode.blockRequest());
configureFlowRule(Integer.MAX_VALUE);
assertFalse(sendRequest(FooRequest.newBuilder().setName("Sentinel").setId(-1).build()));
assertEquals(1, clusterNode.totalException());
configureFlowRule(Integer.MAX_VALUE);
assertTrue(sendRequest(FooRequest.newBuilder().setName("Sentinel").setId(-2).build()));
assertTrue(clusterNode.avgRt() >= 1000);
server.stop();
}
private boolean sendRequest(FooRequest request) {
try {
FooResponse response = client.anotherHello(request);
System.out.println("Response: " + response);
return true;
} catch (StatusRuntimeException ex) {
System.out.println("Blocked, cause: " + ex.getMessage());
return false;
}
}
@Before
public void cleanUpBefore() {
FlowRuleManager.loadRules(null);
ClusterBuilderSlot.getClusterNodeMap().clear();
}
@After
public void cleanUpAfter() {
FlowRuleManager.loadRules(null);
ClusterBuilderSlot.getClusterNodeMap().clear();
}
}

View File

@@ -0,0 +1,22 @@
syntax = "proto3";
option java_multiple_files = true;
option java_package = "com.alibaba.csp.sentinel.adapter.grpc.gen";
option java_outer_classname = "FooProto";
package com.alibaba.sentinel.examples;
message FooRequest {
string name = 1;
int32 id = 2;
}
message FooResponse {
string message = 1;
}
// Example service definition.
service FooService {
rpc sayHello(FooRequest) returns (FooResponse) {}
rpc anotherHello(FooRequest) returns (FooResponse) {}
}