Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

gRPC: What is the recommended way to shut down an asynchronous server in C++?

I have a gRPC server that hosts two asynchronous services ("Master" and "Worker"), and I would like to implement graceful shutdown for the server. Each service has its own grpc::CompletionQueue.

There appear to be two Shutdown() methods that might be relevant: grpc::CompletionQueue::Shutdown() and grpc::Server::Shutdown(), but it's not clear from the documentation which ones should be used.

What is a good pattern for shutting down an asynchronous service?

like image 987
mrry Avatar asked Feb 29 '16 19:02

mrry


People also ask

Is gRPC synchronous or asynchronous?

The gRPC programming API in most languages comes in both synchronous and asynchronous flavors. You can find out more in each language's tutorial and reference documentation (complete reference docs are coming soon).

Are gRPC calls asynchronous?

Additionally, a gRPC RPC can be synchronous or asynchronous. Synchronous: a client call waits for the server to respond. Asynchronous: client makes non-blocking calls to the server, and the server returns the response asynchronously.

Is gRPC single threaded?

A gRPC channel uses a single HTTP/2 connection, and concurrent calls are multiplexed on that connection.

What is Channel and stub in gRPC?

A gRPC channel provides a connection to a gRPC server on a specified host and port... Conclude : A channel represents a single TCP connection. stub : On the client side, the client has a local object known as stub (for some languages, the preferred term is client) that implements the same methods as the service.


1 Answers

TL;DR: You must call both grpc::Server::Shutdown() and grpc::CompletionQueue::Shutdown() (for each completion queue used in the service) to shut down cleanly.

  1. If you call cq_->Shutdown(), the only observable effect is that subsequent calls to Service::AsyncService::RequestFoo() (the generated method for the corresponding Foo RPC) fail with an assertion. From reading the documentation of the corresponding C API method (grpc_completion_queue_shutdown()), it appears that it is illegal to add new work to the queue—i.e. by calling RequestFoo()—so I added an is_shutdown_ member to my service wrapper classes (protected by a mutex) so that no enqueue attempts are made after cq_->Shutdown() is called. However, after doing this, the completion queue blocks indefinitely in cq_->Next(). None of the enqueued tags complete (with an error or otherwise).

  2. If instead you call server_->Shutdown(), all of the enqueued tags complete immediately (with ok == false). However, the completion queue continues to block indefinitely in cq_->Next().

Calling both cq_->Shutdown() (for each defined completion queue) and server_->Shutdown() results in a clean shutdown.

One caveat: if you use grpc::ServerContext::AsyncNotifyWhenDone() to register a tag for call cancellation, these will not be returned by cq_->Next() if the server shuts down before the initial request is received for that call. You will need to be cautious with the memory management of the corresponding tag structure, if you want to avoid memory leaks.

like image 81
mrry Avatar answered Sep 17 '22 23:09

mrry