• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 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.errorhandling;
18 
19 import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
20 
21 import com.google.common.base.Verify;
22 import com.google.common.base.VerifyException;
23 import com.google.common.util.concurrent.FutureCallback;
24 import com.google.common.util.concurrent.Futures;
25 import com.google.common.util.concurrent.ListenableFuture;
26 import com.google.common.util.concurrent.Uninterruptibles;
27 import com.google.rpc.DebugInfo;
28 import io.grpc.CallOptions;
29 import io.grpc.ClientCall;
30 import io.grpc.Grpc;
31 import io.grpc.InsecureChannelCredentials;
32 import io.grpc.InsecureServerCredentials;
33 import io.grpc.ManagedChannel;
34 import io.grpc.Metadata;
35 import io.grpc.Server;
36 import io.grpc.Status;
37 import io.grpc.examples.helloworld.GreeterGrpc;
38 import io.grpc.examples.helloworld.GreeterGrpc.GreeterBlockingStub;
39 import io.grpc.examples.helloworld.GreeterGrpc.GreeterFutureStub;
40 import io.grpc.examples.helloworld.GreeterGrpc.GreeterStub;
41 import io.grpc.examples.helloworld.HelloReply;
42 import io.grpc.examples.helloworld.HelloRequest;
43 import io.grpc.protobuf.ProtoUtils;
44 import io.grpc.stub.StreamObserver;
45 import java.util.concurrent.CountDownLatch;
46 import java.util.concurrent.ExecutionException;
47 import java.util.concurrent.TimeUnit;
48 import javax.annotation.Nullable;
49 
50 /**
51  * Shows how to setting and reading RPC error details.
52  * Proto used here is just an example proto, but the pattern sending
53  * application error information as an application-specific binary protos
54  * in the response trailers is the recommended way to return application
55  * level error.
56  */
57 public class DetailErrorSample {
58   private static final Metadata.Key<DebugInfo> DEBUG_INFO_TRAILER_KEY =
59       ProtoUtils.keyForProto(DebugInfo.getDefaultInstance());
60 
61   private static final DebugInfo DEBUG_INFO =
62       DebugInfo.newBuilder()
63           .addStackEntries("stack_entry_1")
64           .addStackEntries("stack_entry_2")
65           .addStackEntries("stack_entry_3")
66           .setDetail("detailed error info.").build();
67 
68   private static final String DEBUG_DESC = "detailed error description";
69 
main(String[] args)70   public static void main(String[] args) throws Exception {
71     new DetailErrorSample().run();
72   }
73 
74   private ManagedChannel channel;
75 
run()76   void run() throws Exception {
77     Server server = Grpc.newServerBuilderForPort(0, InsecureServerCredentials.create())
78         .addService(new GreeterGrpc.GreeterImplBase() {
79       @Override
80       public void sayHello(HelloRequest request, StreamObserver<HelloReply> responseObserver) {
81         Metadata trailers = new Metadata();
82         trailers.put(DEBUG_INFO_TRAILER_KEY, DEBUG_INFO);
83         responseObserver.onError(Status.INTERNAL.withDescription(DEBUG_DESC)
84             .asRuntimeException(trailers));
85       }
86     }).build().start();
87     channel = Grpc.newChannelBuilderForAddress(
88           "localhost", server.getPort(), InsecureChannelCredentials.create()).build();
89 
90     blockingCall();
91     futureCallDirect();
92     futureCallCallback();
93     asyncCall();
94     advancedAsyncCall();
95 
96     channel.shutdown();
97     server.shutdown();
98     channel.awaitTermination(1, TimeUnit.SECONDS);
99     server.awaitTermination();
100   }
101 
verifyErrorReply(Throwable t)102   static void verifyErrorReply(Throwable t) {
103     Status status = Status.fromThrowable(t);
104     Metadata trailers = Status.trailersFromThrowable(t);
105     Verify.verify(status.getCode() == Status.Code.INTERNAL);
106     Verify.verify(trailers.containsKey(DEBUG_INFO_TRAILER_KEY));
107     Verify.verify(status.getDescription().equals(DEBUG_DESC));
108     try {
109       Verify.verify(trailers.get(DEBUG_INFO_TRAILER_KEY).equals(DEBUG_INFO));
110     } catch (IllegalArgumentException e) {
111       throw new VerifyException(e);
112     }
113   }
114 
blockingCall()115   void blockingCall() {
116     GreeterBlockingStub stub = GreeterGrpc.newBlockingStub(channel);
117     try {
118       stub.sayHello(HelloRequest.newBuilder().build());
119     } catch (Exception e) {
120       verifyErrorReply(e);
121     }
122   }
123 
futureCallDirect()124   void futureCallDirect() {
125     GreeterFutureStub stub = GreeterGrpc.newFutureStub(channel);
126     ListenableFuture<HelloReply> response =
127         stub.sayHello(HelloRequest.newBuilder().build());
128 
129     try {
130       response.get();
131     } catch (InterruptedException e) {
132       Thread.currentThread().interrupt();
133       throw new RuntimeException(e);
134     } catch (ExecutionException e) {
135       verifyErrorReply(e.getCause());
136     }
137   }
138 
futureCallCallback()139   void futureCallCallback() {
140     GreeterFutureStub stub = GreeterGrpc.newFutureStub(channel);
141     ListenableFuture<HelloReply> response =
142         stub.sayHello(HelloRequest.newBuilder().build());
143 
144     final CountDownLatch latch = new CountDownLatch(1);
145 
146     Futures.addCallback(
147         response,
148         new FutureCallback<HelloReply>() {
149           @Override
150           public void onSuccess(@Nullable HelloReply result) {
151             // Won't be called, since the server in this example always fails.
152           }
153 
154           @Override
155           public void onFailure(Throwable t) {
156             verifyErrorReply(t);
157             latch.countDown();
158           }
159         },
160         directExecutor());
161 
162     if (!Uninterruptibles.awaitUninterruptibly(latch, 1, TimeUnit.SECONDS)) {
163       throw new RuntimeException("timeout!");
164     }
165   }
166 
asyncCall()167   void asyncCall() {
168     GreeterStub stub = GreeterGrpc.newStub(channel);
169     HelloRequest request = HelloRequest.newBuilder().build();
170     final CountDownLatch latch = new CountDownLatch(1);
171     StreamObserver<HelloReply> responseObserver = new StreamObserver<HelloReply>() {
172 
173       @Override
174       public void onNext(HelloReply value) {
175         // Won't be called.
176       }
177 
178       @Override
179       public void onError(Throwable t) {
180         verifyErrorReply(t);
181         latch.countDown();
182       }
183 
184       @Override
185       public void onCompleted() {
186         // Won't be called, since the server in this example always fails.
187       }
188     };
189     stub.sayHello(request, responseObserver);
190 
191     if (!Uninterruptibles.awaitUninterruptibly(latch, 1, TimeUnit.SECONDS)) {
192       throw new RuntimeException("timeout!");
193     }
194   }
195 
196 
197   /**
198    * This is more advanced and does not make use of the stub.  You should not normally need to do
199    * this, but here is how you would.
200    */
advancedAsyncCall()201   void advancedAsyncCall() {
202     ClientCall<HelloRequest, HelloReply> call =
203         channel.newCall(GreeterGrpc.getSayHelloMethod(), CallOptions.DEFAULT);
204 
205     final CountDownLatch latch = new CountDownLatch(1);
206 
207     call.start(new ClientCall.Listener<HelloReply>() {
208 
209       @Override
210       public void onClose(Status status, Metadata trailers) {
211         Verify.verify(status.getCode() == Status.Code.INTERNAL);
212         Verify.verify(trailers.containsKey(DEBUG_INFO_TRAILER_KEY));
213         try {
214           Verify.verify(trailers.get(DEBUG_INFO_TRAILER_KEY).equals(DEBUG_INFO));
215         } catch (IllegalArgumentException e) {
216           throw new VerifyException(e);
217         }
218 
219         latch.countDown();
220       }
221     }, new Metadata());
222 
223     call.sendMessage(HelloRequest.newBuilder().build());
224     call.halfClose();
225 
226     if (!Uninterruptibles.awaitUninterruptibly(latch, 1, TimeUnit.SECONDS)) {
227       throw new RuntimeException("timeout!");
228     }
229   }
230 }
231 
232