首页 文章

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

提问于
浏览
1

我正在使用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, "");
}

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

2 回答

  • 5

    我正在使用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;
    }
    

    为了使这项工作,我在第二个线程中调用 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();
    

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

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

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

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

  • 0

    您可以从ShutDown()处理程序创建一个std :: function,并在单独的线程(或线程池)中运行该函数 . 这将允许将RPC的处理与关闭逻辑的执行分离,并消除死锁 .

相关问题