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

examples: Health example #9991

Merged
merged 22 commits into from
Mar 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
4afc5b1
checkpoint
larry-safran Mar 22, 2023
bb3faec
Completed health service example.
larry-safran Mar 24, 2023
a0d287a
Everything ready except for bazel dependency problem
larry-safran Mar 24, 2023
5a14ea8
fix bazel
larry-safran Mar 27, 2023
9b25ddc
Add round robin to the example.
larry-safran Mar 29, 2023
aae877e
fixed
larry-safran Mar 29, 2023
09efd9d
disable recording real-time metrics using in gcp-o11y
DNVindhya Mar 21, 2023
caac3f0
gcp-o11y: add sleep in Observability close()
DNVindhya Mar 22, 2023
7b6caef
test/android: fix the import for AndroidJUnit4
zhangkun83 Mar 22, 2023
c5949da
netty: implement GrpcHttp2InboundHeaders.iterator()
zhangkun83 Mar 22, 2023
4002b4e
examples: waitForReady example (#9960)
larry-safran Mar 22, 2023
f618fee
gcp-o11y: add default custom tag for metrics exporter
DNVindhya Mar 22, 2023
21fe4c2
Remove sleep from Observability Interop Test binary now that its done…
stanley-cheung Mar 22, 2023
7581150
examples: add gcp-observability examples (#9967)
DNVindhya Mar 23, 2023
c672d99
examples: Add cancellation example
ejona86 Mar 23, 2023
2d38926
Add support for cross-compiling for s390x platform (#9455)
haubenr Mar 23, 2023
490de36
[Examples] health service example
larry-safran Mar 22, 2023
c43c4fe
fixed
larry-safran Mar 29, 2023
db31ca7
fix build
larry-safran Mar 30, 2023
cebe3e8
Add health service to README.md.
larry-safran Mar 30, 2023
f49f709
Merge branch 'master' into health_example
larry-safran Mar 30, 2023
11f8d06
Address review comments.
larry-safran Mar 30, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
31 changes: 31 additions & 0 deletions examples/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ java_library(
"@io_grpc_grpc_java//netty",
],
deps = [
":_health_java_grpc",
":echo_java_grpc",
":echo_java_proto",
":hello_streaming_java_grpc",
Expand All @@ -93,7 +94,11 @@ java_library(
"@io_grpc_grpc_java//api",
"@io_grpc_grpc_java//context",
"@io_grpc_grpc_java//protobuf",
"@io_grpc_grpc_java//services:health",
"@io_grpc_grpc_java//services:healthlb",
"@io_grpc_grpc_java//stub",
"@io_grpc_grpc_proto//:health_proto",
"@io_grpc_grpc_proto//:health_java_proto",
"@maven//:com_google_api_grpc_proto_google_common_protos",
"@maven//:com_google_code_findbugs_jsr305",
"@maven//:com_google_code_gson_gson",
Expand Down Expand Up @@ -217,3 +222,29 @@ java_binary(
":examples",
],
)

java_binary(
name = "healthservice-server",
testonly = 1,
main_class = "io.grpc.examples.healthservice.HealthServiceServer",
runtime_deps = [
":examples",
],
)

java_binary(
name = "healthservice-client",
testonly = 1,
main_class = "io.grpc.examples.healthservice.HealthServiceClient",
runtime_deps = [
":examples",
],
)

java_grpc_library(
name = "_health_java_grpc",
srcs = ["@io_grpc_grpc_proto//:health_proto"],
visibility = ["//visibility:private"],
deps = ["@io_grpc_grpc_proto//:health_java_proto"],
)

14 changes: 14 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,20 @@ before trying out the examples.

</details>

- <details>
<summary>Health Service</summary>

The [health service example](src/main/java/io/grpc/examples/healthservice)
provides a HelloWorld gRPC server that doesn't like short names along with a
health service. It also provides a client application which makes HelloWorld
calls and checks the health status.

The client application also shows how the round robin load balancer can
utilize the health status to avoid making calls to a service that is
not actively serving.
</details>


- [Keep Alive](src/main/java/io/grpc/examples/keepalive)

### <a name="to-build-the-examples"></a> To build the examples
Expand Down
17 changes: 17 additions & 0 deletions examples/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def protocVersion = protobufVersion

dependencies {
implementation "io.grpc:grpc-protobuf:${grpcVersion}"
implementation "io.grpc:grpc-services:${grpcVersion}"
implementation "io.grpc:grpc-stub:${grpcVersion}"
compileOnly "org.apache.tomcat:annotations-api:6.0.53"

Expand Down Expand Up @@ -223,6 +224,20 @@ task cancellationServer(type: CreateStartScripts) {
classpath = startScripts.classpath
}

task healthServiceServer(type: CreateStartScripts) {
mainClass = 'io.grpc.examples.healthservice.HealthServiceServer'
applicationName = 'health-service-server'
outputDir = new File(project.buildDir, 'tmp/scripts/' + name)
classpath = startScripts.classpath
}

task healthServiceClient(type: CreateStartScripts) {
mainClass = 'io.grpc.examples.healthservice.HealthServiceClient'
applicationName = 'health-service-client'
outputDir = new File(project.buildDir, 'tmp/scripts/' + name)
classpath = startScripts.classpath
}

task multiplexingServer(type: CreateStartScripts) {
mainClass = 'io.grpc.examples.multiplex.MultiplexingServer'
applicationName = 'multiplexing-server'
Expand Down Expand Up @@ -259,6 +274,8 @@ applicationDistribution.into('bin') {
from(deadlineClient)
from(keepAliveServer)
from(keepAliveClient)
from(healthServiceServer)
from(healthServiceClient)
from(cancellationClient)
from(cancellationServer)
from(multiplexingServer)
Expand Down
4 changes: 4 additions & 0 deletions examples/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-services</artifactId>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
/*
* Copyright 2023 The gRPC Authors
*
* 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.grpc.examples.healthservice;

import io.grpc.Channel;
import io.grpc.Grpc;
import io.grpc.InsecureChannelCredentials;
import io.grpc.LoadBalancerProvider;
import io.grpc.LoadBalancerRegistry;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.StatusRuntimeException;
import io.grpc.examples.helloworld.GreeterGrpc;
import io.grpc.examples.helloworld.HelloReply;
import io.grpc.examples.helloworld.HelloRequest;
import io.grpc.health.v1.HealthCheckRequest;
import io.grpc.health.v1.HealthCheckResponse;
import io.grpc.health.v1.HealthCheckResponse.ServingStatus;
import io.grpc.health.v1.HealthGrpc;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* A client that requests a greeting from the {@link HelloWorldServer}.
*/
public class HealthServiceClient {
private static final Logger logger = Logger.getLogger(HealthServiceClient.class.getName());

private final GreeterGrpc.GreeterBlockingStub greeterBlockingStub;
private final HealthGrpc.HealthStub healthStub;
private final HealthGrpc.HealthBlockingStub healthBlockingStub;

private final HealthCheckRequest healthRequest;

/** Construct client for accessing HelloWorld server using the existing channel. */
public HealthServiceClient(Channel channel) {
greeterBlockingStub = GreeterGrpc.newBlockingStub(channel);
healthStub = HealthGrpc.newStub(channel);
healthBlockingStub = HealthGrpc.newBlockingStub(channel);
healthRequest = HealthCheckRequest.getDefaultInstance();
LoadBalancerProvider roundRobin = LoadBalancerRegistry.getDefaultRegistry()
.getProvider("round_robin");

}

private ServingStatus checkHealth(String prefix) {
HealthCheckResponse response =
healthBlockingStub.check(healthRequest);
logger.info(prefix + ", current health is: " + response.getStatus());
return response.getStatus();
}

/** Say hello to server. */
public void greet(String name) {
logger.info("Will try to greet " + name + " ...");
HelloRequest request = HelloRequest.newBuilder().setName(name).build();
HelloReply response;
try {
response = greeterBlockingStub.sayHello(request);
} catch (StatusRuntimeException e) {
logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus());
return;
} catch (Exception e) {
e.printStackTrace();
return;
}
logger.info("Greeting: " + response.getMessage());
}


private static void runTest(String target, String[] users, boolean useRoundRobin)
throws InterruptedException {
ManagedChannelBuilder<?> builder =
Grpc.newChannelBuilder(target, InsecureChannelCredentials.create());

// Round Robin, when a healthCheckConfig is present in the default service configuration, runs
// a watch on the health service and when picking an endpoint will
// consider a transport to a server whose service is not in SERVING state to be unavailable.
// Since we only have a single server we are connecting to, then the load balancer will
// return an error without sending the RPC.
if (useRoundRobin) {
larry-safran marked this conversation as resolved.
Show resolved Hide resolved
builder = builder
.defaultLoadBalancingPolicy("round_robin")
.defaultServiceConfig(generateHealthConfig(""));
}

ManagedChannel channel = builder.build();

System.out.println("\nDoing test with" + (useRoundRobin ? "" : "out")
+ " the Round Robin load balancer\n");

try {
HealthServiceClient client = new HealthServiceClient(channel);
if (!useRoundRobin) {
client.checkHealth("Before call");
}
client.greet(users[0]);
if (!useRoundRobin) {
client.checkHealth("After user " + users[0]);
}

for (String user : users) {
client.greet(user);
Thread.sleep(100); // Since the health update is asynchronous give it time to propagate
}

if (!useRoundRobin) {
client.checkHealth("After all users");
Thread.sleep(10000);
client.checkHealth("After 10 second wait");
} else {
Thread.sleep(10000);
}
client.greet("Larry");
} finally {
// ManagedChannels use resources like threads and TCP connections. To prevent leaking these
// resources the channel should be shut down when it will no longer be used. If it may be used
// again leave it running.
channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS);
}
}
private static Map<String, Object> generateHealthConfig(String serviceName) {
Map<String, Object> config = new HashMap<>();
Map<String, Object> serviceMap = new HashMap<>();

config.put("healthCheckConfig", serviceMap);
serviceMap.put("serviceName", serviceName);
return config;
}

/**
* Uses a server with both a greet service and the health service.
* If provided, the first element of {@code args} is the name to use in the
* greeting. The second argument is the target server.
* This has an example of using the health service directly through the unary call
* <a href="https://github.com/grpc/grpc-java/blob/master/services/src/main/proto/grpc/health/v1/health.proto">check</a>
* to get the current health. It also utilizes the health of the server's greet service
* indirectly through the round robin load balancer, which uses the streaming rpc
* <strong>watch</strong> (you can see how it is done in
* {@link io.grpc.protobuf.services.HealthCheckingLoadBalancerFactory}).
*/
public static void main(String[] args) throws Exception {
System.setProperty("java.util.logging.SimpleFormatter.format",
"%1$tH:%1$tM:%1$tS %4$s %2$s: %5$s%6$s%n");

String[] users = {"world", "foo", "I am Grut"};
// Access a service running on the local machine on port 50051
String target = "localhost:50051";
// Allow passing in the user and target strings as command line arguments
if (args.length > 0) {
if ("--help".equals(args[0])) {
System.err.println("Usage: [target [name] [name] ...]");
System.err.println("");
System.err.println(" target The server to connect to. Defaults to " + target);
System.err.println(" name The names you wish to be greeted by. Defaults to " + Arrays.toString(users));
System.exit(1);
}
target = args[0];
}
if (args.length > 1) {
users = new String[args.length-1];
for (int i=0; i < users.length; i++) {
users[i] = args[i+1];
}
}

// Will see failures of rpc's sent while server service is not serving, where the failures come
// from the server
runTest(target, users, false);

// The client will throw an error when sending the rpc to a non-serving service because the
// round robin load balancer uses the health service's watch rpc.
runTest(target, users, true);

}
}