gRPC - Client Calls



gRPC client supports two types of client calls, i.e., how the client calls the server. Following are the two ways −

  • Blocking client call

  • Async client call

In this chapter, we will look at both of them one by one.

Blocking Client Calls

gRPC supports blocking client call. What this means is that once the client makes the call to the service, the client would not proceed with rest of the code execution until it gets the response back from the server. Note that a blocking client call is possible for unary calls and server streaming calls.

Note that a blocking client call is possible for unary calls and server streaming calls.

Here is an example of a unary blocking client call.

Example

package com.tp.bookstore;

import io.grpc.Channel;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.StatusRuntimeException;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.tp.bookstore.BookStoreOuterClass.Book;
import com.tp.bookstore.BookStoreOuterClass.BookSearch;
import com.tp.greeting.GreeterGrpc;
import com.tp.greeting.Greeting.ServerOutput;
import com.tp.greeting.Greeting.ClientInput;

public class BookStoreClientUnaryBlocking {
   private static final Logger logger = Logger.getLogger(BookStoreClientUnaryBlocking.class.getName());
   private final BookStoreGrpc.BookStoreBlockingStubblockingStub;
   public BookStoreClientUnaryBlocking(Channel channel) {
      blockingStub = BookStoreGrpc.newBlockingStub(channel);
   }
   public void getBook(String bookName) {
      logger.info("Querying for book with title: " + bookName);
      BookSearch request = BookSearch.newBuilder().setName(bookName).build();

      Book response;
      try {
         response = blockingStub.first(request);
      } catch (StatusRuntimeException e) {
         logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus());
         return;
      }
      logger.info("Got following book from server: " + response);
   }
   public static void main(String[] args) throws Exception {
      String bookName = args[0];
      String serverAddress = "localhost:50051";
      ManagedChannel channel = ManagedChannelBuilder.forTarget(serverAddress)
         .usePlaintext()
         .build();
      try {
         BookStoreClientUnaryBlocking client = new
         BookStoreClientUnaryBlocking(channel);
         client.getBook(bookName);
      } finally {
         channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS);
      }
   }
}

In the above example, we have,

public BookStoreClientUnaryBlocking(Channel channel) {
   blockingStub = BookStoreGrpc.newBlockingStub(channel);
}

which means we will be using a blocking RPC call.

And then, we have,

BookSearch request = BookSearch.newBuilder().setName(bookName).build();

Book response;
response = blockingStub.first(request);

This is where we use the blockingStub to call the RPC method first() to get the book details.

Similarly, for server streaming, we can use the blocking stub −

logger.info("Querying for book with author: " + author);
BookSearch request =
BookSearch.newBuilder().setAuthor(author).build();

Iterator<Book> response;
try {
   response = blockingStub.searchByAuthor(request);
   while(response.hasNext()) {
   logger.info("Found book: " + response.next());
}

Where we call the RPC method searchByAuthor method and iterate over the response till the server stream has not ended.

Non-Blocking Client Calls

gRPC supports non-blocking client calls. What this means is that when the client makes a call to the service, it does not need to wait for the server response. To handle the server response, the client can simply pass in the observer which dictates what to do when the response is received. Note that a non-blocking client call is possible for unary calls as well as streaming calls. However, we would specifically look at the case of server streaming call to compare it against a blocking call.

Note that a non-blocking client call is possible for unary calls as well as streaming calls. However, we would specifically look at the case of server streaming call to compare it against a blocking call.

Here is an example of a server streaming non-blocking client call

Example

package com.tp.bookstore;

import io.grpc.Channel;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.StatusRuntimeException;
import io.grpc.stub.StreamObserver;

import java.util.Iterator;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.tp.bookstore.BookStoreOuterClass.Book;
import com.tp.bookstore.BookStoreOuterClass.BookSearch;
import com.tp.greeting.GreeterGrpc;
import com.tp.greeting.Greeting.ServerOutput;
import com.tp.greeting.Greeting.ClientInput;

public class BookStoreClientServerStreamingNonBlocking {
   private static final Logger logger = Logger.getLogger(BookStoreClientServerStreamingNonBlocking.class.getName());
   private final BookStoreGrpc.BookStoreStub nonBlockingStub;
   public BookStoreClientServerStreamingNonBlocking(Channelchannel) {
      nonBlockingStub = BookStoreGrpc.newStub(channel);
   }
   public StreamObserver<Book> getServerResponseObserver(){
      StreamObserver<Book> observer = new
      StreamObserver<Book>(){
         @Override
         public void onNext(Book book) {
            logger.info("Server returned following book: " +book);
         }
         @Override
         public void onError(Throwable t) {
            logger.info("Error while reading response fromServer: " + t);
         }
         @Override
         public void onCompleted() {
            logger.info("Server returned following book: " + book);
         }
      };
      return observer;
   }
   public void getBook(String author) {
      logger.info("Querying for book with author: " + author);
      BookSearch request = BookSearch.newBuilder().setAuthor(author).build();
      try {
         nonBlockingStub.searchByAuthor(request,getServerResponseObserver());
      } catch (StatusRuntimeException e) {
         logger.log(Level.WARNING, "RPC failed: {0}",e.getStatus());
         return;
      }
   }
   public static void main(String[] args) throws Exception {
      String authorName = args[0];
      String serverAddress = "localhost:50051";
      ManagedChannel channel =ManagedChannelBuilder.forTarget(serverAddress)
         .usePlaintext()
         .build();
      try {
         BookStoreClientServerStreamingNonBlocking client = new
         BookStoreClientServerStreamingNonBlocking(channel);
         client.getBook(authorName);
      } finally {
         channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS);
      }
   }
}

As we see in the above example,

public BookStoreClientUnaryNonBlocking(Channel channel) {
   nonBlockingStub = BookStoreGrpc.newStub(channel);
}

It defines that the stub is a non-blocking one. Similarly, the following code is used to handle the response that we get from the server. Once the server sends the response, we log the output.

public StreamObserver<Book> getServerResponseObserver(){
   StreamObserver<Book> observer = new
   StreamObserver<Book>(){
   ....
   ....
   return observer;
}

The following gRPC call is a non-blocking call.

logger.info("Querying for book with author: " + author);
BookSearch request = BookSearch.newBuilder().setAuthor(author).build();
try {
   nonBlockingStub.searchByAuthor(request, getServerResponseObserver());
}

This is how we ensure that our client does not need to wait till we have the server complete the execution of searchByAuthor. That would be handled directly by the stream observer object as and when the server returns the Book objects.

Advertisements