RetryPolicy 中的 perAttemptRecvTimeout 没有任何作用
作者: vlad1147创建于 2026年7月21日更新于 2026年9月11日
标签bug
你使用了哪个版本的 gRPC-Java? 1.76.0(但最新版本中也有同样的问题) ### 你的环境是什么?搭载了 gprc-java 和 grpc-android 库的 Android 应用程序 ### 你期望看到什么? https://GitHub.com/grpc/grpc-java/pull/8301 将 perAttemptRecvTimeoutNanos 添加到 RetryPolicy 中,但问题在于它从未被使用,因此无法在 gRPC 调用中为尝试设置超时。我不确定,但可能与此问题 https://GitHub.com/grpc/grpc-java/issues/1943 有关 ### 你看到的结果是什么?我期望 RetriableStream 使用来自 RetryPolicy 的 perAttemptRecvTimeoutNanos,因此 makeRetryDecision 实际上会在尝试持续时间超过 perAttemptRecvTimeoutNanos 所指定的时间时重试 ### 如何重现错误?可以使用任何通道和具有 perAttemptRecvTimeout 的 RetryPolicy 重现此错误 ### 为什么我需要它? 我正在寻找一种方法来检测和恢复应用程序中出现的黑洞 gRPC 连接。我从生产环境中获得了包含 DEADLINE_EXCEEDED 异常的日志,其中或有 waiting_for_connection 或 remote_addr=/10.0.2.2:8443(这是来自本地测试,但重点是生产环境中存在 remote_addr)。据我所知,在第一种情况下,通道处于 CONNECTING 状态,而在第二种情况下处于 READY 状态,但它们都无法成功,后端没有错误。我通过使用 toxiproxy 在本地重现了该问题,并模拟了黑洞连接。我的想法是在 RetryPolicy 中传递 perAttemptRecvTimeout,这样我就可以依赖 gRPC 内部重试机制,并在尝试失败时使用 DEADLINE_EXCEEDED 来调用 channel.enterIdle(与 AndroidChannelBuilder 在检测到网络变化时所做的一样,以强制为下一次调用建立新连接)(与刷新过期授权令牌的思想相同,但没有 CallCredentials,因为这里建议了它,并且它在我们的应用程序中确实起作用 https://GitHub.com/grpc/grpc-java/issues/7345#issuecomment-679295003)
object : ClientStreamTracer.Factory() {
override fun newClientStreamTracer(
info: ClientStreamTracer.StreamInfo,
headers: Metadata,
): ClientStreamTracer = object : ClientStreamTracer() {
override fun streamClosed(status: Status) {
if (status.code == Status.Code.DEADLINE_EXCEEDED) {
channel.enterIdle()
}
}
}
}我也考虑了 keepAlive 选项,但它似乎没有像上面的想法那样平滑地工作,而且如果我没有弄错的话 - 当通道处于 CONNECTING 状态时,它不会从黑洞连接中恢复,因为它只适用于已建立的连接,因此通道必须处于 READY 状态。此外,它会耗费电池并向后端发送垃圾数据。 我也考虑过使用重试拦截器,但我担心这是一种脆弱的方法,此前曾给我们带来了很多麻烦
内容来源: grpc/grpc-java