Skip to content

fix(gax): do not treat a SocketTimeoutException as a thread interrupt - #14778

Merged
lqiu96 merged 1 commit into
googleapis:mainfrom
lqiu96:fix/gax-socket-timeout-not-interrupt
Oct 26, 2026
Merged

lqiu96 merged 1 commit into
googleapis:mainfrom
lqiu96:fix/gax-socket-timeout-not-interrupt

Conversation

@lqiu96

@lqiu96 lqiu96 commented Oct 26, 2026 •

Copy link
Copy Markdown
Member

Fixes #12860

This PR originally created by @markaddleman (thanks for the contribution!). Re-created on this PR to resolve the merge conflicts.

Summary

Supersedes #14578 (recreated with merge conflicts resolved in DirectRetryingExecutorTest).

DirectRetryingExecutor.submit catches InterruptedIOException and sets the current thread's interrupt flag. SocketTimeoutException extends InterruptedIOException, so an HTTP connect or read timeout also sets the flag, although no thread was interrupted. setAttemptFuture then calls Future.get, which sees the flag and throws a new InterruptedException. The SocketTimeoutException is lost, and the retry algorithm judges an InterruptedException in its place. A caller sees an InterruptedException from an unknown sender.

This change catches SocketTimeoutException first and passes it to the retry algorithm unchanged. A real interrupt (InterruptedException, any other InterruptedIOException, ClosedByInterruptException) keeps the current path.

DirectRetryingExecutor.submit catches InterruptedIOException and sets the current thread's interrupt flag. SocketTimeoutException extends InterruptedIOException, so an HTTP connect or read timeout also sets the flag, although no thread was interrupted. setAttemptFuture then calls Future.get, which sees the flag and throws a new InterruptedException. The SocketTimeoutException is lost, and the retry algorithm judges an InterruptedException in its place. A caller sees an InterruptedException from an unknown sender.

Catch SocketTimeoutException first and give it to the retry algorithm unchanged. A real interrupt (InterruptedException, other InterruptedIOException, ClosedByInterruptException) keeps the old path.

Supersedes googleapis#14578

Related to googleapis#12860

Co-authored-by: Mark Addleman <markaddleman@gmail.com>
@lqiu96
lqiu96 requested a review from a team as a code owner October 26, 2026 18:46

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request modifies DirectRetryingExecutor to explicitly catch SocketTimeoutException separately from other InterruptedIOException instances. Because a socket timeout represents a network timeout rather than a thread interruption, handling it separately prevents the thread's interrupt flag from being set, allowing the retry algorithm to properly evaluate and retry the timeout. Corresponding unit tests have been added to verify this behavior. There are no review comments to evaluate, and I have no additional feedback to provide as the implementation is correct and well-tested.

@lqiu96
lqiu96 merged commit 7b91805 into googleapis:main Oct 26, 2026
286 of 297 checks passed
jinseopkim0 pushed a commit that referenced this pull request Nov 3, 2026
🤖 I have created a release *beep* *boop*
---


<details><summary>1.95.0</summary>

##
[1.95.0](v1.94.0...v1.95.0)
(2026-11-02)


### Features

* **bigquery-jdbc:** expose BigQueryResultSetMetadata and getField(int)
([#14761](#14761))
([f01245a](f01245a))
* **gax:** align resumable upload chunk size to server granularity and
surface effective chunk size
([#14670](#14670))
([6cbb096](6cbb096))
* **google/cloud/designcenter/v1:** add designcenter
([#14823](#14823))
([01d27dc](01d27dc))
* **google/cloud/observability/v1:** add observability
([#14722](#14722))
([624f28e](624f28e))
* **oauth2:** support certificate-bound OAuth2 tokens and mTLS rotation
for Workload Identity Federation
([#14781](#14781))
([dcb29b0](dcb29b0))
* **storage:** add bucket IP filtering samples and tests
([#14328](#14328))
([cb2b726](cb2b726))
* **storage:** add support for DirectPath over Interconnect
([#14006](#14006))
([ad0eb94](ad0eb94))
* **storage:** OpenTelemetry client metrics configuration and options
([#14484](#14484))
([7c29e48](7c29e48))
* **storage:** OpenTelemetry client metrics instrument registry and
views
([#14398](#14398))
([60233b7](60233b7))


### Bug Fixes

* add user agent to session path
([#14835](#14835))
([a653638](a653638))
* **auth:** align mTLS transport and bound token certificate startup
polling and well-known discovery
([#14748](#14748))
([0bae268](0bae268))
* **bigquery-jdbc:** expand handling to OOM errors
([#14759](#14759))
([7d4b921](7d4b921))
* **bigquery-jdbc:** fix naive fallback of parameter count
([#14779](#14779))
([c3e4a5b](c3e4a5b))
* **bigquery-jdbc:** format RANGE bounds consistently across REST and
Arrow
([#14807](#14807))
([2108b8e](2108b8e))
* **bigquery-jdbc:** parse scientific-notation epoch TIMESTAMPs
([#14777](#14777))
([71a31b1](71a31b1))
* **bigquery-jdbc:** preserve pre-1582 and pre-standard-time
DATE/DATETIME digits
([#14787](#14787))
([3dc394f](3dc394f))
* **bigtable:** avoid mutating Query in-place in createPointReadCallable
([#14797](#14797))
([1b1c6a7](1b1c6a7))
* **bigtable:** check isOk and getRejected first in
RetryingVRpc.shouldRetry
([#14795](#14795))
([d821bd3](d821bd3))
* **bigtable:** check remaining deadline on client-initiated retries in
RetryingVRpc
([#14796](#14796))
([a04e24c](a04e24c))
* **bigtable:** Fix empty RowResult semantics in TestProxy.
([#14810](#14810))
([1d2fb9a](1d2fb9a))
* **bigtable:** include reversed in Query equals, hashCode, and toString
([#14799](#14799))
([fe9232b](fe9232b))
* **bigtable:** pass cell value size to RowBuilder.startCell in
RowBuilderShim
([#14800](#14800))
([cfa7949](cfa7949))
* **bigtable:** reject empty split points in RowSetUtil and clarify
QueryPaginator Javadoc
([#14811](#14811))
([1bc507f](1bc507f))
* **bigtable:** remove legacy PollingConfiguration migration in
ClientConfigurationManager
([#14822](#14822))
([95ead45](95ead45))
* **bigtable:** resolve session diversion through a single shared rule
([#14738](#14738))
([00f7bea](00f7bea))
* **bigtable:** respect query limit smaller than pageSize and avoid
mutating Query in QueryPaginator
([#14821](#14821))
([cecd09e](cecd09e))
* **firestore:** graduate pipeline search from preview to GA
([#14741](#14741))
([a993026](a993026))
* **gax:** do not treat a SocketTimeoutException as a thread interrupt
([#14778](#14778))
([7b91805](7b91805))
* **jdbc:** populate `ResultSetMetaData` on empty `DatabaseMetaData`
resultsets
([#14809](#14809))
([4c6a7e3](4c6a7e3))
* **pubsub:** make publish hedging robust to clock jumps, queue errors,
and shutdown
([#14860](#14860))
([9b9e2a5](9b9e2a5))
* **spanner:** attach routing hints to read-write transaction requests
([#14786](#14786))
([54e0585](54e0585))
* **spanner:** cancel queries promptly on close and synchronize error
handling
([#14887](#14887))
([323a8f7](323a8f7))
* **spanner:** do not cache retryable errors in AbstractLazyInitializer
([#14752](#14752))
([6a9ac76](6a9ac76))
* **spanner:** restore setCall overload for stream test compatibility
([#14885](#14885))
([cfe728e](cfe728e))
* **spanner:** synchronize stream lifecycle and retry buffering in
ResumableStreamIterator
([#14770](#14770))
([4edefc5](4edefc5))
* **spanner:** trigger best-effort rollback on indeterminate commit
failures
([#14831](#14831))
([b9d1b95](b9d1b95))
* **storage:** preserve HTTP status for XML multipart upload errors so
retries work
([#14804](#14804))
([3c03034](3c03034))
* **storage:** send destination on gRPC copy when target BlobInfo is
provided
([#14784](#14784))
([43a67a0](43a67a0))
* **storage:** validate CRC32C on HTTP downloads that were not
decompressed
([#14805](#14805))
([61aa22f](61aa22f))


### Documentation

* **bigtable:** document that skipped large rows count towards row limit
([#14801](#14801))
([91d60e0](91d60e0))
</details>

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

---------

Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[sdk-platform-java] DirectRetryingExecutor re-interrupts the thread before recording interrupt-related attempt failure

2 participants