Declaring a gRPC service method that returns an optional response

98 views
Skip to first unread message

John Coffey

unread,
Jun 6, 2017, 1:48:31 PM6/6/17
to grpc.io
I am creating an RPC service and I want to know how I would declare an RPC method that returns (in my case) an optional response.  The way the rpc is defined below means that it always returns a PageResponse.  I suppose I could check to see if the page_title in the response has not been set but I am sure that there is a more elegant solution to this (probably a combination of 'empty' and 'oneof'?

Also in a somewhat related question, Is it possible to change the rpc to support some sort of push data?  I have a cache managed by a GWService and I would like the grpc client to act like a listener for updates to this cache - other than polling for changes, I am not sure how I would do this.  Is that what streaming is for? 

Thanks in advance

John

//! Request a page object from the cache
message PageRequest {
    string page_title   = 1;
}

//! cache page wrapper
message PageResponse {
    // embed the page title in case we decide to stream 
    // many of these back to back using the streaming API
    string page_title   = 1;
    Page page_data   = 2;
}

//! Gateway Service.
service GWService {
   . . .

   // request a specific  
   rpc GetPage(PageRequest) returns (PageResponse) {}
}

Vijay Pai

unread,
Jun 6, 2017, 2:21:52 PM6/6/17
to John Coffey, grpc.io
You're on the right track with regard to the first question. A unary RPC has to have a response, but the response can be empty (which you can check with the appropriate has_ methods) or you can do a oneof. An alternative is to use a server-side streaming return value which allows 0 or more responses 

   rpc GetPage(PageRequest) returns (stream PageResponse)

And that ties in to the 2nd question re Push  - that's exactly what streaming is for. You can send your updates back as subsequent responses on the return stream. Hope that helps!
@vjpai

--
You received this message because you are subscribed to the Google Groups "grpc.io" group.
To unsubscribe from this group and stop receiving emails from it, send an email to grpc-io+u...@googlegroups.com.
To post to this group, send email to grp...@googlegroups.com.
Visit this group at https://groups.google.com/group/grpc-io.
To view this discussion on the web visit https://groups.google.com/d/msgid/grpc-io/4e8ac2d7-2811-4098-af3a-c8ea34cb04bc%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

John Coffey

unread,
Jun 6, 2017, 9:51:42 PM6/6/17
to grpc.io, joh...@gmail.com
Vijay, thanks, yes very helpful.  

On the streaming side - I'm not familiar with the intricacies of how the streaming works.   After your suggestion, I found the RouteGuide example and was looking through it to try to understand exactly how the streaming works.  The example declares the ListFeatures rpc method as a streaming method as follows:

rpc ListFeatures(Rectangle) returns (stream Feature) {}

However looking at the client C++ code, it looks almost like a synchronous API that returns the current list of features at the time of the call (albeit returned in streaming form).  In my case, I would like to have a dedicated thread waiting for updates from the server (I'm essentially monitoring a page of data for updates).  I'm not sure this is possible without repeatedly polling which would be different to streaming.  I'm new to the grpc streaming so I am probably incorrect.

John

  void ListFeatures() {
    routeguide::Rectangle rect;
    Feature feature;
    ClientContext context;

    rect.mutable_lo()->set_latitude(400000000);
    rect.mutable_lo()->set_longitude(-750000000);
    rect.mutable_hi()->set_latitude(420000000);
    rect.mutable_hi()->set_longitude(-730000000);
    std::cout << "Looking for features between 40, -75 and 42, -73"
              << std::endl;

    std::unique_ptr<ClientReader<Feature> > reader(
        stub_->ListFeatures(&context, rect));
    while (reader->Read(&feature)) {
      std::cout << "Found feature called "
                << feature.name() << " at "
                << feature.location().latitude()/kCoordFactor_ << ", "
                << feature.location().longitude()/kCoordFactor_ << std::endl;
    }
    Status status = reader->Finish();
    if (status.ok()) {
      std::cout << "ListFeatures rpc succeeded." << std::endl;
    } else {
      std::cout << "ListFeatures rpc failed." << std::endl;
    }
  }

Vijay Pai

unread,
Jun 7, 2017, 2:09:29 PM6/7/17
to John Coffey, grpc.io
So the synchronous stream Read operation just matches a stream Write operation on the other side. If the other side (server in your case) hasn't issued a Write operation yet, your Read will block until it comes. Your Read operation isn't busy-polling, it's blocking and waiting in this case. That's the value of doing it in a separate thread as you've described.

- Vijay

Reply all
Reply to author
Forward
0 new messages