Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

perAttemptRecvTimeout in RetryPolicy does nothing

未关闭
#12,919 3 条评论 19 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

@waterWang 已经在做这个了。

开始于 2026年7月29日。

  • #12939 来自 @waterWang —— 未关闭

评估

难度
4/5
预计耗时
3-5 天
新手友好度
55/100
Issue 类型
缺陷
描述清晰度
基本清楚
活跃度
活跃
技术栈
android, java

调研方向

首先跟踪 RetryPolicy 和 RetriableStream,重点关注 perAttemptRecvTimeoutNanos 如何到达 makeRetryDecision。使用已报告的黑洞场景,或使用等效的 channel 和 RetryPolicy,验证超过配置超时的尝试会产生 DEADLINE_EXCEEDED,并触发预期的重试行为。

由索引模型根据 Issue 内容生成。

描述

bug
What version of gRPC-Java are you using?

1.76.0 (but it's the same problem in the latest release too)

What is your environment?

Android app with gprc-java and grpc-android libs

What did you expect to see?

https://github.com/grpc/grpc-java/pull/8301 added perAttemptRecvTimeoutNanos to the RetryPolicy but the problem that it's never used so it's not possible to set a timeout for an attempt within the gRPC call. Not sure but might be related to this issue https://github.com/grpc/grpc-java/issues/1943

What did you see instead?

I would expect RetriableStream to use perAttemptRecvTimeoutNanos from RetryPolicy so makeRetryDecision will actually retry when an attempt takes longer than specified in perAttemptRecvTimeoutNanos

Steps to reproduce the bug

Can be reproduced with any channel and RetryPolicy that has perAttemptRecvTimeout.

A bit of context why do I even need it

I'm looking for a way to detect and recover from a black hole gRPC connection that happens in my app.
I have logs from production with DEADLINE_EXCEEDED exception that either has waiting_for_connection or remote_addr=/10.0.2.2:8443 (it's from local test but the point that there is a remote_addr in production). As far as I understand in the first case the channel is in CONNECTING state and in the second is in READY but neither of them can succeed and backend has no errors. I reproduced the issue locally by using toxiproxy and simulated a black hole connection. My idea is to pass perAttemptRecvTimeout in RetryPolicy so I can rely on gRPC internal retry mechanism and when an attempt fails with DEADLINE_EXCEEDED to call channel.enterIdle (same as AndroidChannelBuilder does when detects the change in network to force a new connection for the next call) in ClientStreamFactory (same idea as for refreshing an expired auth token but without CallCredentials as was suggested here and it actually works in our app 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()
                }
            }
        }
    }

I also considered keepAlive option but it doesn't seems to work as smooth as the idea above and if I'm not wrong - it will not recover from a black hole connection when the channel is in CONNECTING because it's only sent for an established connection so the channel has to be in READY state. And also it will drain battery and spam the backend.

Also I thought to have a retry interceptor but I'm afraid it's a fragile approach that previously caused us a lot of crashes when it was attempted for token refresh and retry afterwards. (Probably it's possible to implement it flawlessly but it likely it will be difficult to understand and easy to break in the future and therefore not considered).

And as a last resort it's also possible to use try/catch and retry on the call-site and manage the channel there but it requires to change every single call-site in the app and can be easily forgotten for new calls. So not a sustainable option.

Just wanted to share what I already thought of and I believe the first suggestion that uses perAttemptRecvTimeout is the best among listed approaches. I would be happy to hear if there are other possible robust ways to fix it.

主要语言
Java
星标
12.1k
派生
4k
平均合并
2 天 6 小时
30 天内合并 PR
26

环境准备

  • 没有 Dockerfile 或 Docker Compose 文件
  • 没有 Pull Request 模板
  • 阅读贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

grpc/grpc-java 的其他 Issue

查看 grpc/grpc-java 的全部 Issue

相似的 Issue

更多 Java Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。