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.keepalive; 18 19 import io.grpc.Grpc; 20 import io.grpc.InsecureServerCredentials; 21 import io.grpc.Server; 22 import io.grpc.examples.helloworld.GreeterGrpc; 23 import io.grpc.examples.helloworld.HelloReply; 24 import io.grpc.examples.helloworld.HelloRequest; 25 import io.grpc.stub.StreamObserver; 26 import java.io.IOException; 27 import java.util.concurrent.TimeUnit; 28 import java.util.logging.Logger; 29 30 /** 31 * Server that manages startup/shutdown of a keep alive server. 32 */ 33 public class KeepAliveServer { 34 private static final Logger logger = Logger.getLogger(KeepAliveServer.class.getName()); 35 36 private Server server; 37 start()38 private void start() throws IOException { 39 /* The port on which the server should run */ 40 int port = 50051; 41 42 // Start a server with the following configurations (demo only, you should set more appropriate 43 // values based on your real environment): 44 // keepAliveTime: Ping the client if it is idle for 5 seconds to ensure the connection is 45 // still active. Set to an appropriate value in reality, e.g. in minutes. 46 // keepAliveTimeout: Wait 1 second for the ping ack before assuming the connection is dead. 47 // Set to an appropriate value in reality, e.g. (10, TimeUnit.SECONDS). 48 // permitKeepAliveTime: If a client pings more than once every 5 seconds, terminate the 49 // connection. 50 // permitKeepAliveWithoutCalls: Allow pings even when there are no active streams. 51 // maxConnectionIdle: If a client is idle for 15 seconds, send a GOAWAY. 52 // maxConnectionAge: If any connection is alive for more than 30 seconds, send a GOAWAY. 53 // maxConnectionAgeGrace: Allow 5 seconds for pending RPCs to complete before forcibly closing 54 // connections. 55 // Use JAVA_OPTS=-Djava.util.logging.config.file=logging.properties to see keep alive ping 56 // frames. 57 // More details see: https://github.com/grpc/proposal/blob/master/A9-server-side-conn-mgt.md 58 server = Grpc.newServerBuilderForPort(port, InsecureServerCredentials.create()) 59 .addService(new GreeterImpl()) 60 .keepAliveTime(5, TimeUnit.SECONDS) 61 .keepAliveTimeout(1, TimeUnit.SECONDS) 62 .permitKeepAliveTime(5, TimeUnit.SECONDS) 63 .permitKeepAliveWithoutCalls(true) 64 .maxConnectionIdle(15, TimeUnit.SECONDS) 65 .maxConnectionAge(30, TimeUnit.SECONDS) 66 .maxConnectionAgeGrace(5, TimeUnit.SECONDS) 67 .build() 68 .start(); 69 logger.info("Server started, listening on " + port); 70 Runtime.getRuntime().addShutdownHook(new Thread() { 71 @Override 72 public void run() { 73 // Use stderr here since the logger may have been reset by its JVM shutdown hook. 74 System.err.println("*** shutting down gRPC server since JVM is shutting down"); 75 try { 76 KeepAliveServer.this.stop(); 77 } catch (InterruptedException e) { 78 e.printStackTrace(System.err); 79 } 80 System.err.println("*** server shut down"); 81 } 82 }); 83 } 84 stop()85 private void stop() throws InterruptedException { 86 if (server != null) { 87 server.shutdown().awaitTermination(30, TimeUnit.SECONDS); 88 } 89 } 90 91 /** 92 * Await termination on the main thread since the grpc library uses daemon threads. 93 */ blockUntilShutdown()94 private void blockUntilShutdown() throws InterruptedException { 95 if (server != null) { 96 server.awaitTermination(); 97 } 98 } 99 100 /** 101 * Main launches the server from the command line. 102 */ main(String[] args)103 public static void main(String[] args) throws IOException, InterruptedException { 104 final KeepAliveServer server = new KeepAliveServer(); 105 server.start(); 106 server.blockUntilShutdown(); 107 } 108 109 static class GreeterImpl extends GreeterGrpc.GreeterImplBase { 110 111 @Override sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver)112 public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) { 113 HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName()).build(); 114 responseObserver.onNext(reply); 115 responseObserver.onCompleted(); 116 } 117 } 118 } 119