perAttemptRecvTimeout in RetryPolicy does nothing
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 55/100
- issue の種類
- バグ
- 明瞭さ
- おおむね明確
- 活発さ
- 活発
調査の方向性
まず RetryPolicy と RetriableStream を追跡し、perAttemptRecvTimeoutNanos がどのように makeRetryDecision に到達するかに注目します。報告されたブラックホールのシナリオ、または同等の channel と RetryPolicy を使用して、設定されたタイムアウトを超えた試行が DEADLINE_EXCEEDED を生成し、期待される retry 動作をトリガーすることを確認します。
索引モデルが issue の本文から書いたものです。
説明
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日 3時間
- マージ済み PR(30日)
- 30
環境構築
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
grpc/grpc-java のほかの issue
-
enhancement
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
grpc/grpc-java#13063 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
grpc/grpc-java#13052 · コメント 4 件 ·
メンテナーはふだん 1 日以内に返信
-
docs enhancement
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
grpc/grpc-java#10824 · コメント 8 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 4/5 3〜5日 初心者へのやさしさ 70/100
メンテナーはふだん 1 日以内に返信
-
難易度 3/5 1〜2日 初心者へのやさしさ 65/100
メンテナーはふだん 1 日以内に返信
似ている issue
-
link-check link-check:manual
難易度 2/5 1〜3時間 初心者へのやさしさ 85/100
-
難易度 1/5 1時間未満 初心者へのやさしさ 91/100
open-telemetry/opentelemetry-java#8870 ·
メンテナーはふだん 1 日以内に返信
-
P2 testing
難易度 1/5 1時間未満 初心者へのやさしさ 90/100
メンテナーはふだん 1 日以内に返信
-
enhancement javascript
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
メンテナーはふだん 1 日以内に返信
-
area/core kind/bug status/triage team/core-shared
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
メンテナーはふだん 1 日以内に返信