1 /* 2 * Copyright 2023 The gRPC Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package io.grpc.examples.waitforready; 18 19 import io.grpc.Channel; 20 import io.grpc.Deadline; 21 import io.grpc.Grpc; 22 import io.grpc.InsecureChannelCredentials; 23 import io.grpc.ManagedChannel; 24 import io.grpc.StatusRuntimeException; 25 import io.grpc.examples.helloworld.GreeterGrpc; 26 import io.grpc.examples.helloworld.HelloRequest; 27 import io.grpc.examples.helloworld.HelloReply; 28 import java.util.concurrent.TimeUnit; 29 import java.util.logging.Level; 30 import java.util.logging.Logger; 31 32 /** 33 * This is an example of using waitForReady. This is a feature which can be used on a stub 34 * which will cause the rpcs to wait (until optional deadline is exceeded) for the 35 * server to become available before sending the request. This is useful for batch workflows 36 * where there is no need to fail fast. 37 * 38 * Below is a simple client that requests a greeting from the 39 * {@link io.grpc.examples.helloworld.HelloWorldServer} and defines waitForReady on the stub. 40 * To test, 41 * 1. run this client without a server running - client rpc should hang 42 * 2. start the server - client rpc should complete 43 * 3. run this client again - client rpc should complete nearly immediately 44 */ 45 public class WaitForReadyClient { 46 private static final Logger logger = Logger.getLogger(WaitForReadyClient.class.getName()); 47 48 private final GreeterGrpc.GreeterBlockingStub blockingStub; 49 50 /** 51 * Construct client for accessing HelloWorld server using the existing channel which will 52 * wait for the server to become ready, however long that may take, before sending the request. 53 */ WaitForReadyClient(Channel channel)54 public WaitForReadyClient(Channel channel) { 55 // This is the only difference from the simple HelloWorld example 56 blockingStub = GreeterGrpc.newBlockingStub(channel).withWaitForReady(); 57 } 58 59 /** 60 * Construct a client for accessing HelloWorld server using the existing channel which will 61 * wait for the server to become ready, up to the specified deadline, before sending the request. 62 * if the deadline is exceeded before the server becomes ready, then the rpc call will fail with 63 * a Status of DEADLINE_EXCEEDED without the request being sent. 64 */ WaitForReadyClient(Channel channel, Deadline deadline)65 public WaitForReadyClient(Channel channel, Deadline deadline) { 66 blockingStub = GreeterGrpc.newBlockingStub(channel).withWaitForReady().withDeadline(deadline); 67 } 68 69 70 /** Say hello to server. */ greet(String name)71 public void greet(String name) { 72 logger.info("Will try to greet " + name + " ..."); 73 HelloRequest request = HelloRequest.newBuilder().setName(name).build(); 74 HelloReply response; 75 try { 76 response = blockingStub.sayHello(request); 77 } catch (StatusRuntimeException e) { 78 logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus()); 79 return; 80 } 81 logger.info("Greeting: " + response.getMessage()); 82 } 83 84 /** 85 * Greet server. If provided, the first element of {@code args} is the name to use in the 86 * greeting. The second argument is the target server. 87 */ main(String[] args)88 public static void main(String[] args) throws Exception { 89 String user = "world"; 90 // Access a service running on the local machine on port 50051 91 String target = "localhost:50051"; 92 // Allow passing in the user and target strings as command line arguments 93 if (args.length > 0) { 94 if ("--help".equals(args[0])) { 95 System.err.println("Usage: [name [target]]"); 96 System.err.println(); 97 System.err.println(" name The name you wish to be greeted by. Defaults to " + user); 98 System.err.println(" target The server to connect to. Defaults to " + target); 99 System.exit(1); 100 } 101 user = args[0]; 102 } 103 if (args.length > 1) { 104 target = args[1]; 105 } 106 107 // Create a communication channel to the server, known as a Channel. Channels are thread-safe 108 // and reusable. It is common to create channels at the beginning of your application and reuse 109 // them until the application shuts down. 110 // 111 // For the example we use plaintext insecure credentials to avoid needing TLS certificates. To 112 // use TLS, use TlsChannelCredentials instead. 113 ManagedChannel channel = Grpc.newChannelBuilder(target, InsecureChannelCredentials.create()) 114 .build(); 115 try { 116 // If server isn't running, this will fail after 5 seconds. Will also fail if the server is 117 // running particularly slowly and takes more than 5 minutes to respond. 118 WaitForReadyClient clientWithTimeout = 119 new WaitForReadyClient(channel, Deadline.after(5, TimeUnit.SECONDS)); 120 clientWithTimeout.greet(user); 121 122 // This will wait forever until the server becomes ready 123 WaitForReadyClient client = new WaitForReadyClient(channel); 124 client.greet(user); 125 } finally { 126 // ManagedChannels use resources like threads and TCP connections. To prevent leaking these 127 // resources the channel should be shut down when it will no longer be used. If it may be used 128 // again leave it running. 129 channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS); 130 } 131 } 132 } 133