An asynchronous interface for gRPC based on callbacks. While gRPC already provides an asynchronous interface, it is quite low-level. gRPC has an experimental (as of 2020/07/10, still in progress) higher-level asynchronous interface based on a reactor pattern, it is still based on inheritance and overriding virtual functions to receive "callbacks" and as such is hard to compose with other asynchronous code. Moreover, it's still relatively low-level, e.g., it only permits a single write at a time, requiring users to buffer writes on their own.
eventuals-grpc
is intended to be a higher-level inteface while still being asynchronous that uses (eventuals
)[[https://github.com/3rdparty/eventuals] to make composing asynchronous code easy. It's design favors lambdas, as Usage below should make clear. It deliberately tries to mimic grpc
naming where appropriate to simplify understanding across interfaces.
Please see Known Limitations and Suggested Improvements below for more insight into the limits of the inteface.
Examples can be found here.
They have been put in a separate repository to make it easier to clone that repository and start building a project rather than trying to figure out what pieces of the build should be copied.
We recommend cloning the examples and building them in order to play around with the library.
We suggest starting with the examples above, as they provide a good template for how you might embed this library into your own project.
Currently we only support Bazel and expect/use C++17.
You can build the library with:
$ bazel build :grpc
...
You can build and run the tests with:
$ bazel test test:grpc
...
glog is used to perform logging. You'll need to enable glog verbose logging by setting the environment variable GLOG_v=1
(or any value greater than 1) as well as the enironment variable EVENTUALS_GRPC_LOG=1
. You can call google::InitGoogleLogging(argv[0]);
in your own main()
function to properly initialize glog.
-
Services can not (yet) be removed after they are "added" via
Server::Accept()
. -
One of the key design requirements was being able to add a "service" dynamically, i.e., after the server has started, by calling
Server::Accept()
. This doesn't play nicely with some built-in components of gRPC, such as server reflection (see below). In the short-term we'd like to support adding services before the server starts that under the covers useRegisterService()
so that those services can benefit from any built-in components of gRPC. -
Server Reflection via the (gRPC Server Reflection Protocol)[https://github.com/grpc/grpc/blob/master/doc/server-reflection.md] requires that all services are registered before the server starts. Because
eventuals::grpc::Server
is designed to allow services to be added dynamically via invokingServer::Accept()
at any point during runtime, the reflection server started viagrpc::reflection::InitProtoReflectionServerBuilderPlugin()
will not know about any of the services. One possibility is to build a new implementation of the reflection server that works with dynamic addition/removal of services. A short-term possibility is to only support server reflection for services added before the server starts. -
No check is performed that all methods of a particular service are added via
Server::Accept()
. In practice, this probably won't be an issue as agrpc::UNIMPLEMENTED
will get returned which is similar to how a lot of services get implemented incrementally (i.e., they implement one method at a time and return agrpc::UNIMPLEMENTED
until they get to said method).