创建通道和存根时,如何检查 RPC 客户端是否确实成功连接到 RPC 服务器?
我希望能够在连接失败时抛出异常或信号。我不确定什么方法有资格在这里尝试“操作”。我不想进行我们定义的任何 RPC 调用,因为它们都会产生影响......除非唯一的选择是实现一些“嗨,我在这里”RPC 方法,但这看起来很愚蠢, 不?
void ChatSyncClient::connect(QUrl const& endpoint)
{
disconnect();
// TODO - How do we tell if this fails?
// The comments say a lame channel will be returned, where all operations fail
// How are we suppose to check right here rather than later?
auto channel = ::grpc::CreateChannel(endpoint.toString().toStdString(), ::grpc::InsecureChannelCredentials());
m_stub = std::make_unique<chat_sync::Chat::Stub>(channel);
emit signalOnConnected();
}
Run Code Online (Sandbox Code Playgroud)
小智 25
在我直接回答你的问题之前,让我先提供一些背景知识。
gRPC 通道实际上与连接不同。事实上,一个通道可能有多个并行活动的底层连接,具体取决于通道使用的负载平衡策略。通道 API 的目的是从应用程序中抽象出各个连接的详细信息;这个想法是,应用程序应该将通道视为发送 RPC 的通用接口,通道将在内部自动处理连接管理的细节,因此应用程序不必担心它们。
因此,从较高的层面来看,我认为您的应用程序不需要知道或关心通道是否已连接。如果您认为确实需要知道这一点,那么我实际上会认为这表明您需要退一步并重新思考如何构建应用程序。
特别是,我不确定您所说的“我不想进行我们定义的任何 RPC 调用,因为它们都会产生影响”到底是什么意思,但这对我来说听起来有点奇怪。我假设您的意思是可能会对服务器的状态产生影响,这意味着 RPC 不是幂等的。您可能需要考虑以某种方式将其更改为幂等,因为这样更安全(我会在一分钟内回到原因)。但即使您正在处理非幂等 RPC,我也不知道了解底层连接的状态如何帮助您避免该问题。即使通道在客户端启动 RPC 时已连接,也永远不能保证服务器会看到它,因为连接可能会在应用程序告诉 gRPC 发送它之后但在它在线上发出之前失败。或者,在 gRPC 将其上线后,网络本身可能无法将其传送到服务器。或者,更糟糕的是,服务器可以看到它,但在服务器响应返回客户端之前网络可能会发生故障。实际上并不能保证 RPC 是原子的,也不能保证客户端和服务器对 RPC 是否成功有相同的看法。在任何这些情况下,客户端所知道的只是 RPC 失败,但它无法从中推断服务器是否确实看到了 RPC。
这就是为什么将 RPC 设计为幂等通常更有意义。您可以关注各个 RPC 是否成功,而不是关注通道是否已连接。每当客户端发现 RPC 失败时,它都可以重试。如果服务器碰巧两次看到相同的 RPC,那不会破坏事情(例如,如果您重播删除操作,它会注意到数据已被删除,因此它将是一个无操作)。
因此,我的高级答案是,您的客户端代码应该对单个 RPC 失败做出反应,而不是对连接失败做出反应。
综上所述,如果您确实想要监视通道的连接状态,则可以使用连接状态 API来实现。请注意,gRPC 通道实际上不会在您创建时立即启动连接。最初,它处于 IDLE 状态。当 (a) 您在通道上发送第一个 RPC 或 (b) 您调用显式要求它连接时,它将尝试连接(并转换到状态 CONNECTING)channel->GetState(true)。如果连接尝试失败,通道将转换为 TRANSIENT_FAILURE 状态,并且会定期重试。当它建立连接时,它将转换到状态 READY。
在处于 TRANSIENT_FAILURE 状态的通道上发送的任何 RPC 都将立即失败,除非它处于wait_for_ready 状态。对于当通道转换到 TRANSIENT_FAILURE 状态时仍处于待处理状态的 RPC 也是如此(例如,如果通道最初处于 IDLE 状态并由于 RPC 发送而开始连接,但随后初始连接尝试失败) 。
关于蹩脚通道,请注意,这种情况只会在极少数情况下发生,即您尝试使用 gRPC 不知道如何解析的格式错误的目标 URI 创建通道。如果 gRPC 知道它永远无法解析您指定的名称,它将返回一个蹩脚的通道,这基本上是一个永久处于 TRANSIENT_FAILURE 状态的通道。
我希望这些信息对你有用。