如何从客户端关闭gRPC服务器(使用RPC功能)

use*_*929 0 c++ grpc

我正在使用gRPC进行C++ App(gRPC Server)和Java App(gRPC Client)之间的进程间通信.一切都在一台机器上运行.我想提供客户端关闭服务器的可能性.我的想法是在proto中添加RPC函数来进行服务.

C++实现将是:

class Service : public grpcGeneratedService
{
public:
......
private:  
    grpc::Server* m_pServer;
};
grpc::Status Service::ShutDown(grpc::ServerContext* pContext, const ShutDownRequest* pRequest, ShutDownResponse* pResponse)
{
    if (m_pServer)
        m_pServer->Shutdown();
    return grpc::Status(grpc::StatusCode::OK, "");
}
Run Code Online (Sandbox Code Playgroud)

但是,ShutDown会阻塞,直到所有RPC调用都被处理,这意味着死锁.有没有优雅的方法如何实现它?

小智 8

我正在使用std :: promise,其方法几乎和你的一样.

// Somewhere in the global scope :/
std::promise<void> exit_requested;

// My method looks nearly identical to yours 
Status CoreServiceImpl::shutdown(ServerContext *context, const SystemRequest *request, Empty*)
{
  LOG(INFO) << context->peer() << " - Shutdown request acknowledged.";
  exit_requested.set_value();
  return Status::OK;
}
Run Code Online (Sandbox Code Playgroud)

为了使这项工作,我server->Wait()在第二个线程中调用并等待将来exit_requested阻止关闭调用的承诺:

auto serveFn = [&]() {
  server->Wait();
};

std::thread serving_thread(serveFn);

auto f = exit_requested.get_future();
f.wait();
server->Shutdown();
serving_thread.join();
Run Code Online (Sandbox Code Playgroud)

一旦我有了这个,我也能够通过信号处理程序支持干净关闭:

auto handler = [](int s) {
  exit_requested.set_value();
};
std::signal(SIGINT, handler);
std::signal(SIGTERM, handler);
std::signal(SIGQUIT, handler);
Run Code Online (Sandbox Code Playgroud)

到目前为止,我对这种方法感到满意,它使我保持在gRPC和标准c ++库的范围内.而不是使用一些全局范围的承诺(我必须在服务实现源中将其声明为外部)我应该想到更优雅的东西.

这里需要注意的一点是,多次设置promise的值会引发异常.如果您以某种方式同时发送关闭消息,则可能会发生这种情况pkill -2 my_awesome_service.当我的持久层中出现死锁以防止关闭完成时,我实际上遇到了这种情况,当我尝试再次发送SIGINT时,服务中止了!对于我的需求,这仍然是一个可接受的解决方案,但我很想知道解决这个小问题的替代方案.

  • 唔。[其他问答强烈建议](/sf/answers/3711378961/) 在信号处理程序中设置 Promise 的值是未定义的行为(不在信号安全函数列表中)。这是一种耻辱。但是除了有关信号处理程序的业务之外,好的答案谢谢! (3认同)