From df310fe2b5a02f99e2a04cc69a4c0434fbe66f0b Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Fri, 4 Dec 2015 15:46:11 -0800 Subject: [PATCH] More precise exception handling in examples Try to make it clear how failures propagate and provide hints on how to get more error information. --- .../examples/header/CustomHeaderClient.java | 15 +- .../examples/header/CustomHeaderServer.java | 5 +- .../examples/helloworld/HelloWorldClient.java | 14 +- .../examples/helloworld/HelloWorldServer.java | 5 +- .../examples/routeguide/RouteGuideClient.java | 151 ++++++++++-------- .../examples/routeguide/RouteGuideServer.java | 4 +- 6 files changed, 111 insertions(+), 83 deletions(-) diff --git a/examples/src/main/java/io/grpc/examples/header/CustomHeaderClient.java b/examples/src/main/java/io/grpc/examples/header/CustomHeaderClient.java index eacab8b374..6c1bb00807 100644 --- a/examples/src/main/java/io/grpc/examples/header/CustomHeaderClient.java +++ b/examples/src/main/java/io/grpc/examples/header/CustomHeaderClient.java @@ -36,6 +36,7 @@ import io.grpc.ClientInterceptor; import io.grpc.ClientInterceptors; import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; +import io.grpc.StatusRuntimeException; import io.grpc.examples.helloworld.GreeterGrpc; import io.grpc.examples.helloworld.HelloRequest; import io.grpc.examples.helloworld.HelloResponse; @@ -74,14 +75,16 @@ public class CustomHeaderClient { * A simple client method that like {@link io.grpc.examples.helloworld.HelloWorldClient}. */ private void greet(String name) { + logger.info("Will try to greet " + name + " ..."); + HelloRequest request = HelloRequest.newBuilder().setName(name).build(); + HelloResponse response; try { - logger.info("Will try to greet " + name + " ..."); - HelloRequest request = HelloRequest.newBuilder().setName(name).build(); - HelloResponse response = blockingStub.sayHello(request); - logger.info("Greeting: " + response.getMessage()); - } catch (RuntimeException e) { - logger.log(Level.WARNING, "RPC failed", e); + response = blockingStub.sayHello(request); + } catch (StatusRuntimeException e) { + logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus()); + return; } + logger.info("Greeting: " + response.getMessage()); } /** diff --git a/examples/src/main/java/io/grpc/examples/header/CustomHeaderServer.java b/examples/src/main/java/io/grpc/examples/header/CustomHeaderServer.java index d64db35bb7..b1ac139342 100644 --- a/examples/src/main/java/io/grpc/examples/header/CustomHeaderServer.java +++ b/examples/src/main/java/io/grpc/examples/header/CustomHeaderServer.java @@ -39,6 +39,7 @@ import io.grpc.examples.helloworld.HelloRequest; import io.grpc.examples.helloworld.HelloResponse; import io.grpc.stub.StreamObserver; +import java.io.IOException; import java.util.logging.Logger; /** @@ -52,7 +53,7 @@ public class CustomHeaderServer { private static final int port = 50051; private Server server; - private void start() throws Exception { + private void start() throws IOException { server = ServerBuilder.forPort(port) .addService(ServerInterceptors.intercept( GreeterGrpc.bindService(new GreeterImpl()), new HeaderServerInterceptor())) @@ -88,7 +89,7 @@ public class CustomHeaderServer { /** * Main launches the server from the command line. */ - public static void main(String[] args) throws Exception { + public static void main(String[] args) throws IOException, InterruptedException { final CustomHeaderServer server = new CustomHeaderServer(); server.start(); server.blockUntilShutdown(); diff --git a/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldClient.java b/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldClient.java index 4b90564b78..3d70a99dc1 100644 --- a/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldClient.java +++ b/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldClient.java @@ -33,6 +33,7 @@ package io.grpc.examples.helloworld; import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; +import io.grpc.StatusRuntimeException; import java.util.concurrent.TimeUnit; import java.util.logging.Level; @@ -61,15 +62,16 @@ public class HelloWorldClient { /** Say hello to server. */ public void greet(String name) { + logger.info("Will try to greet " + name + " ..."); + HelloRequest request = HelloRequest.newBuilder().setName(name).build(); + HelloResponse response; try { - logger.info("Will try to greet " + name + " ..."); - HelloRequest request = HelloRequest.newBuilder().setName(name).build(); - HelloResponse response = blockingStub.sayHello(request); - logger.info("Greeting: " + response.getMessage()); - } catch (RuntimeException e) { - logger.log(Level.WARNING, "RPC failed", e); + response = blockingStub.sayHello(request); + } catch (StatusRuntimeException e) { + logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus()); return; } + logger.info("Greeting: " + response.getMessage()); } /** diff --git a/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldServer.java b/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldServer.java index 8dc6ece8eb..ea0b4fd6d0 100644 --- a/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldServer.java +++ b/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldServer.java @@ -35,6 +35,7 @@ import io.grpc.Server; import io.grpc.ServerBuilder; import io.grpc.stub.StreamObserver; +import java.io.IOException; import java.util.logging.Logger; /** @@ -47,7 +48,7 @@ public class HelloWorldServer { private int port = 50051; private Server server; - private void start() throws Exception { + private void start() throws IOException { server = ServerBuilder.forPort(port) .addService(GreeterGrpc.bindService(new GreeterImpl())) .build() @@ -82,7 +83,7 @@ public class HelloWorldServer { /** * Main launches the server from the command line. */ - public static void main(String[] args) throws Exception { + public static void main(String[] args) throws IOException, InterruptedException { final HelloWorldServer server = new HelloWorldServer(); server.start(); server.blockUntilShutdown(); diff --git a/examples/src/main/java/io/grpc/examples/routeguide/RouteGuideClient.java b/examples/src/main/java/io/grpc/examples/routeguide/RouteGuideClient.java index fdba93becd..2548a058b6 100644 --- a/examples/src/main/java/io/grpc/examples/routeguide/RouteGuideClient.java +++ b/examples/src/main/java/io/grpc/examples/routeguide/RouteGuideClient.java @@ -31,17 +31,19 @@ package io.grpc.examples.routeguide; -import com.google.common.util.concurrent.SettableFuture; - import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; +import io.grpc.Status; +import io.grpc.StatusRuntimeException; import io.grpc.examples.routeguide.RouteGuideGrpc.RouteGuideBlockingStub; import io.grpc.examples.routeguide.RouteGuideGrpc.RouteGuideStub; import io.grpc.stub.StreamObserver; +import java.io.IOException; import java.util.Iterator; import java.util.List; import java.util.Random; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; @@ -73,24 +75,26 @@ public class RouteGuideClient { * Blocking unary call example. Calls getFeature and prints the response. */ public void getFeature(int lat, int lon) { - try { - info("*** GetFeature: lat={0} lon={1}", lat, lon); + info("*** GetFeature: lat={0} lon={1}", lat, lon); - Point request = Point.newBuilder().setLatitude(lat).setLongitude(lon).build(); - Feature feature = blockingStub.getFeature(request); - if (RouteGuideUtil.exists(feature)) { - info("Found feature called \"{0}\" at {1}, {2}", - feature.getName(), - RouteGuideUtil.getLatitude(feature.getLocation()), - RouteGuideUtil.getLongitude(feature.getLocation())); - } else { - info("Found no feature at {0}, {1}", - RouteGuideUtil.getLatitude(feature.getLocation()), - RouteGuideUtil.getLongitude(feature.getLocation())); - } - } catch (RuntimeException e) { - logger.log(Level.WARNING, "RPC failed", e); - throw e; + Point request = Point.newBuilder().setLatitude(lat).setLongitude(lon).build(); + + Feature feature; + try { + feature = blockingStub.getFeature(request); + } catch (StatusRuntimeException e) { + logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus()); + return; + } + if (RouteGuideUtil.exists(feature)) { + info("Found feature called \"{0}\" at {1}, {2}", + feature.getName(), + RouteGuideUtil.getLatitude(feature.getLocation()), + RouteGuideUtil.getLongitude(feature.getLocation())); + } else { + info("Found no feature at {0}, {1}", + RouteGuideUtil.getLatitude(feature.getLocation()), + RouteGuideUtil.getLongitude(feature.getLocation())); } } @@ -99,26 +103,27 @@ public class RouteGuideClient { * response feature as it arrives. */ public void listFeatures(int lowLat, int lowLon, int hiLat, int hiLon) { + info("*** ListFeatures: lowLat={0} lowLon={1} hiLat={2} hiLon={3}", lowLat, lowLon, hiLat, + hiLon); + + Rectangle request = + Rectangle.newBuilder() + .setLo(Point.newBuilder().setLatitude(lowLat).setLongitude(lowLon).build()) + .setHi(Point.newBuilder().setLatitude(hiLat).setLongitude(hiLon).build()).build(); + Iterator features; try { - info("*** ListFeatures: lowLat={0} lowLon={1} hiLat={2} hiLon={3}", lowLat, lowLon, hiLat, - hiLon); - - Rectangle request = - Rectangle.newBuilder() - .setLo(Point.newBuilder().setLatitude(lowLat).setLongitude(lowLon).build()) - .setHi(Point.newBuilder().setLatitude(hiLat).setLongitude(hiLon).build()).build(); - Iterator features = blockingStub.listFeatures(request); - - StringBuilder responseLog = new StringBuilder("Result: "); - while (features.hasNext()) { - Feature feature = features.next(); - responseLog.append(feature); - } - info(responseLog.toString()); - } catch (RuntimeException e) { - logger.log(Level.WARNING, "RPC failed", e); - throw e; + features = blockingStub.listFeatures(request); + } catch (StatusRuntimeException e) { + logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus()); + return; } + + StringBuilder responseLog = new StringBuilder("Result: "); + while (features.hasNext()) { + Feature feature = features.next(); + responseLog.append(feature); + } + info(responseLog.toString()); } /** @@ -126,9 +131,9 @@ public class RouteGuideClient { * features} with a variable delay in between. Prints the statistics when they are sent from the * server. */ - public void recordRoute(List features, int numPoints) throws Exception { + public void recordRoute(List features, int numPoints) throws InterruptedException { info("*** RecordRoute"); - final SettableFuture finishFuture = SettableFuture.create(); + final CountDownLatch finishLatch = new CountDownLatch(1); StreamObserver responseObserver = new StreamObserver() { @Override public void onNext(RouteSummary summary) { @@ -139,19 +144,21 @@ public class RouteGuideClient { @Override public void onError(Throwable t) { - finishFuture.setException(t); + Status status = Status.fromThrowable(t); + logger.log(Level.WARNING, "RecordRoute Failed: {0}", status); + finishLatch.countDown(); } @Override public void onCompleted() { - finishFuture.set(null); + info("Finished RecordRoute"); + finishLatch.countDown(); } }; StreamObserver requestObserver = asyncStub.recordRoute(responseObserver); try { // Send numPoints points randomly selected from the features list. - StringBuilder numMsg = new StringBuilder(); Random rand = new Random(); for (int i = 0; i < numPoints; ++i) { int index = rand.nextInt(features.size()); @@ -161,29 +168,31 @@ public class RouteGuideClient { requestObserver.onNext(point); // Sleep for a bit before sending the next one. Thread.sleep(rand.nextInt(1000) + 500); - if (finishFuture.isDone()) { - break; + if (finishLatch.getCount() == 0) { + // RPC completed or errored before we finished sending. + // Sending further requests won't error, but they will just be thrown away. + return; } } - info(numMsg.toString()); - requestObserver.onCompleted(); - - finishFuture.get(); - info("Finished RecordRoute"); - } catch (Exception e) { + } catch (RuntimeException e) { + // Cancel RPC requestObserver.onError(e); - logger.log(Level.WARNING, "RecordRoute Failed", e); throw e; } + // Mark the end of requests + requestObserver.onCompleted(); + + // Receiving happens asynchronously + finishLatch.await(1, TimeUnit.MINUTES); } /** * Bi-directional example, which can only be asynchronous. Send some chat messages, and print any * chat messages that are sent from the server. */ - public void routeChat() throws Exception { + public void routeChat() throws InterruptedException { info("*** RoutChat"); - final SettableFuture finishFuture = SettableFuture.create(); + final CountDownLatch finishLatch = new CountDownLatch(1); StreamObserver requestObserver = asyncStub.routeChat(new StreamObserver() { @Override @@ -194,12 +203,15 @@ public class RouteGuideClient { @Override public void onError(Throwable t) { - finishFuture.setException(t); + Status status = Status.fromThrowable(t); + logger.log(Level.WARNING, "RouteChat Failed: {0}", status); + finishLatch.countDown(); } @Override public void onCompleted() { - finishFuture.set(null); + info("Finished RouteChat"); + finishLatch.countDown(); } }); @@ -213,19 +225,28 @@ public class RouteGuideClient { .getLatitude(), request.getLocation().getLongitude()); requestObserver.onNext(request); } - requestObserver.onCompleted(); - - finishFuture.get(); - info("Finished RouteChat"); - } catch (Exception t) { - requestObserver.onError(t); - logger.log(Level.WARNING, "RouteChat Failed", t); - throw t; + } catch (RuntimeException e) { + // Cancel RPC + requestObserver.onError(e); + throw e; } + // Mark the end of requests + requestObserver.onCompleted(); + + // Receiving happens asynchronously + finishLatch.await(1, TimeUnit.MINUTES); } /** Issues several different requests and then exits. */ - public static void main(String[] args) throws Exception { + public static void main(String[] args) throws InterruptedException { + List features; + try { + features = RouteGuideUtil.parseFeatures(RouteGuideUtil.getDefaultFeaturesFile()); + } catch (IOException ex) { + ex.printStackTrace(); + return; + } + RouteGuideClient client = new RouteGuideClient("localhost", 8980); try { // Looking for a valid feature @@ -238,7 +259,7 @@ public class RouteGuideClient { client.listFeatures(400000000, -750000000, 420000000, -730000000); // Record a few randomly selected points from the features file. - client.recordRoute(RouteGuideUtil.parseFeatures(RouteGuideUtil.getDefaultFeaturesFile()), 10); + client.recordRoute(features, 10); // Send and receive some notes. client.routeChat(); diff --git a/examples/src/main/java/io/grpc/examples/routeguide/RouteGuideServer.java b/examples/src/main/java/io/grpc/examples/routeguide/RouteGuideServer.java index c713eb6909..ff24ab0297 100644 --- a/examples/src/main/java/io/grpc/examples/routeguide/RouteGuideServer.java +++ b/examples/src/main/java/io/grpc/examples/routeguide/RouteGuideServer.java @@ -208,7 +208,7 @@ public class RouteGuideServer { @Override public void onError(Throwable t) { - logger.log(Level.WARNING, "Encountered error in recordRoute", t); + logger.log(Level.WARNING, "recordRoute cancelled"); } @Override @@ -247,7 +247,7 @@ public class RouteGuideServer { @Override public void onError(Throwable t) { - logger.log(Level.WARNING, "Encountered error in routeChat", t); + logger.log(Level.WARNING, "routeChat cancelled"); } @Override