【问题标题】:How to shutdown gRPC server from Client (using RPC function)如何从客户端关闭 gRPC 服务器(使用 RPC 功能)
【发布时间】:2015-12-06 21:04:29
【问题描述】:

我正在使用 gRPC 在 C++ 应用程序(gRPC 服务器)和 Java 应用程序(gRPC 客户端)之间进行进程间通信。一切都在一台机器上运行。我想为客户端提供关闭服务器的可能性。我的想法是在 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, "");
}

但是,在处理完所有 RPC 调用之前,ShutDown 会阻塞,这意味着死锁。有什么优雅的方式来实现它吗?

【问题讨论】:

    标签: c++ grpc


    【解决方案1】:

    我使用的 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-&gt;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++ 库的范围内。而不是使用一些全局范围的承诺(我必须在我的服务实现源中将其声明为外部的)我可能应该考虑一些更优雅的东西。

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

    【讨论】:

    • 嗯。 [其他问答强烈建议](stackoverflow.com/a/53019699/751579) 在信号处理程序中设置承诺的值是未定义的行为(不在信号安全函数列表中)。这是一种耻辱。但除了关于信号处理程序的业务,好的答案谢谢!
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 2020-04-03
      • 1970-01-01
      • 2019-04-05
      • 2016-10-06
      • 1970-01-01
      • 2017-02-11
      • 2022-01-13
      • 1970-01-01
      • 2021-04-10
      相关资源
      最近更新 更多