Skip to content

Commit 73abb48

Browse files
authored
core: Fix inFlightSubStreams counting on retry commit (#12649)
This PR fixes a race condition in RetriableStream where, under certain retry and deadline timings, the response future may never be completed. When a deadline cancellation occurs concurrently with retry commit, inFlightSubStreams may not be decremented, causing `ClientCallImpl.ClientStreamListenerImpl.closed` to never be invoked. As a result, blockingUnaryCall can hang indefinitely. After this change, the inFlightSubStreams counting is consistent whenever a scheduled retry is committed, ensuring the close signal is always delivered. I verified this using the issue reproduction code from the issue reporter, which previously caused blockingUnaryCall to hang and eventually hit a TimeoutException because a while loop never progressed. After this change, running the same reproduction code no longer hangs and continues as expected without timing out. Fixes #12620
1 parent 024fdd0 commit 73abb48

File tree

1 file changed

+6
-3
lines changed

1 file changed

+6
-3
lines changed

core/src/main/java/io/grpc/internal/RetriableStream.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,8 @@ private Runnable commit(final Substream winningSubstream) {
166166

167167
final boolean wasCancelled = (scheduledRetry != null) ? scheduledRetry.isCancelled() : false;
168168
final Future<?> retryFuture;
169-
if (scheduledRetry != null) {
169+
final boolean retryWasScheduled = scheduledRetry != null;
170+
if (retryWasScheduled) {
170171
retryFuture = scheduledRetry.markCancelled();
171172
scheduledRetry = null;
172173
} else {
@@ -190,8 +191,10 @@ public void run() {
190191
substream.stream.cancel(CANCELLED_BECAUSE_COMMITTED);
191192
}
192193
}
193-
if (retryFuture != null) {
194-
retryFuture.cancel(false);
194+
if (retryWasScheduled) {
195+
if (retryFuture != null) {
196+
retryFuture.cancel(false);
197+
}
195198
if (!wasCancelled && inFlightSubStreams.decrementAndGet() == Integer.MIN_VALUE) {
196199
assert savedCloseMasterListenerReason != null;
197200
listenerSerializeExecutor.execute(

0 commit comments

Comments
 (0)