C++ Asynchronous Interface

1,038 views
Skip to first unread message

shak...@gmail.com

unread,
Jul 19, 2017, 11:32:35 PM7/19/17
to grpc.io
Hi, I'm trying to understand how to convert an application using synchronous RPC to asynchronous. My old method for synchronous communication was calling RegisterService on all my services, then calling Wait() on the server after it was created. The gRPC library would decide which Service function to call from that point. 

When I look at the async C++ example, the beginning looks very similar where the services are added, and BuildAndStart is called. But instead of calling Wait(). HandleRpcs is called as the busy loop. However, it looks like HandleRpcs is only handling a single type of service. I don't see any examples of adding multiple services anywhere, so I'm not sure how that's handled. Does it imply that I would have to make essentially a separate ServerImpl class for every type of service?

Arpit Baldeva

unread,
Jul 20, 2017, 4:43:13 PM7/20/17
to grpc.io, shak...@gmail.com
You can add as many services as you like to a single server (using RegisterService call).

Check out the following post for a better (but complicated sample) https://groups.google.com/forum/#!topic/grpc-io/DuBDpK96B14 . It does not show multiple services but that part is not complicated. 

Cliff Burdick

unread,
Jul 20, 2017, 11:09:55 PM7/20/17
to Arpit Baldeva, grpc.io
Thanks! This is much more helpful than the example in the documentation.

shak...@gmail.com

unread,
Jul 21, 2017, 11:42:43 AM7/21/17
to grpc.io, shak...@gmail.com
Hi Arpit, I had a couple follow-up questions:

I'm looking at your code and mine, and how multiple services might be supported. It seems like the "Request*" function is the one that blocks on a service type, and you essentially need to have create a different CallData (or TagInfo in your case) for every type of Service. Is that right? I only want to have a single thread handling the requests coming in, so I believe I should make a new CallData/TagInfo for every type of Service I have at the start, then sit in a busy loop on my only thread calling Next on the completion queue. It seems like the cleanest way to do that is something similar to what you have, where every Service type implements its own CallData/TagInfo class to do the processing it needs to do for each function. Does all this sound okay?

Arpit Baldeva

unread,
Jul 24, 2017, 2:19:57 PM7/24/17
to grpc.io, shak...@gmail.com
Hi,

The tagInfo/callData can be whatever you want. In the example I attached, the 4 different rpc implementations encapsulate all the state machinery that async gRPC needs in a manner that is transparent to rest of the application code. The tagInfo just 'ends up' at the right state. 

The idea is to provide meaningful implementation of the 'RpcHandlers' when your application instantiates the rpc. That implementation can be per rpc (as I have done in the sample - for example, each rpc gets it's own processor implementation) or can be per service etc. It just depends on how your application is set up. My application is adding gRPC support in addition to our current rpc framework so what I do is simply figure out the existing handler in the implementation of those methods and route the rpc appropriately (This is not how example I attached is set up btw).

For threading, yes, I have a dedicated thread for processing completion queue. It's not a busy loop though - the completion queue internally yields.

I have re-attached a new sample that is simplified than the one I attached earlier. This is pretty much a cleaned up version of what I use in my app today. This one adds the error handling capabilities and makes sending rpc responses and their lifetime management easier.

HTH.
servermain.cpp
Reply all
Reply to author
Forward
Message has been deleted
Message has been deleted
0 new messages