[BUG] RequestRetryOptions tryTimeout has no effect on synchronous Storage clients
メンテナーはふだん 1 日以内に返信
@browndav-msft がすでに取り組んでいます。
2026年11月6日 から。
評価
この issue はまだ評価されていません。
説明
Describe the bug
For synchronous Storage clients (for example BlobServiceClient), the per-try timeout configured with RequestRetryOptions (tryTimeout) never fires. A stalled request runs until the HTTP client's own timeout (60 s by default for Netty) instead of the configured try timeout. The async client with the same options times out as expected.
Root cause
RequestRetryPolicy.attemptSync runs each try as:
Mono<HttpResponse> httpResponseMono = Mono.fromCallable(() -> next.clone().processSync());
httpResponseMono = httpResponseMono.timeout(this.requestRetryOptions.getTryTimeoutDuration());
HttpResponse response = httpResponseMono.block();
Mono.fromCallable runs the blocking processSync() on the subscribing thread inside request(n). In FluxTimeout.TimeoutMainSubscriber.onSubscribe, actual.onSubscribe(this) (which triggers request(n) and therefore the whole blocking call) runs before firstTimeout.subscribe(timeoutSubscriber) arms the timer. By the time the timer is armed, the value has already been emitted, so the timeout can never fire. attemptAsync is not affected because process() does not block on subscribe.
Stack of a sync call blocked on a stalled server (trimmed):
reactor.core.publisher.Mono.block(Mono.java:1779)
com.azure.core.http.netty.NettyAsyncHttpClient.sendSync(NettyAsyncHttpClient.java:194)
...
com.azure.storage.common.policy.RequestRetryPolicy.lambda$attemptSync$0(RequestRetryPolicy.java:266)
reactor.core.publisher.MonoCallable$MonoCallableSubscription.request(MonoCallable.java:137)
reactor.core.publisher.Operators$MultiSubscriptionSubscriber.request(Operators.java:2330)
reactor.core.publisher.SerializedSubscriber.request(SerializedSubscriber.java:151)
To Reproduce
Point a client at a server that accepts the TCP connection but never responds (a ServerSocket that is never accept()ed is enough), with maxTries = 1 and tryTimeout = 1s.
Code Snippet
import com.azure.storage.blob.BlobServiceClientBuilder;
import com.azure.storage.common.StorageSharedKeyCredential;
import com.azure.storage.common.policy.RequestRetryOptions;
import com.azure.storage.common.policy.RetryPolicyType;
import java.net.ServerSocket;
import java.time.OffsetDateTime;
public class TryTimeoutRepro {
public static void main(String[] args) throws Exception {
// The listen backlog completes the TCP handshake, but nothing is ever written back.
try (ServerSocket stalled = new ServerSocket(0)) {
BlobServiceClientBuilder builder = new BlobServiceClientBuilder()
.endpoint("http://127.0.0.1:" + stalled.getLocalPort() + "/devstoreaccount1")
.credential(new StorageSharedKeyCredential("devstoreaccount1",
"Eby8vdM02xNOcqCfGfP/mkP3+rZTt5tF5If1fMvj08QzZLOiT4E5lZaz0smU4wFwbIsrpPoIQx=="))
.retryOptions(new RequestRetryOptions(RetryPolicyType.EXPONENTIAL,
1 /* maxTries */, 1 /* tryTimeoutInSeconds */, null, null, null));
OffsetDateTime start = OffsetDateTime.now();
long t0 = System.nanoTime();
try {
builder.buildAsyncClient().getUserDelegationKey(start, start.plusHours(1)).block();
} catch (RuntimeException e) {
System.out.println("async: " + e.getCause() + " after " + ms(t0) + " ms");
}
t0 = System.nanoTime();
try {
builder.buildClient().getUserDelegationKey(start, start.plusHours(1));
} catch (RuntimeException e) {
System.out.println("sync: " + e + " after " + ms(t0) + " ms");
}
}
}
private static long ms(long t0) {
return (System.nanoTime() - t0) / 1_000_000;
}
}
Observed with an equivalent test:
- async:
TimeoutExceptionafter ~1009 ms - sync: still running after 5000 ms; each try only ends at the HTTP client's 60 s response timeout (two tries took ~120 s)
The same behavior in plain Reactor:
Mono.fromCallable(() -> { Thread.sleep(4000); return "OK"; })
.timeout(Duration.ofSeconds(1))
.block(); // returns "OK" after ~4001 ms, no timeout
Mono.fromCallable(() -> { Thread.sleep(4000); return "OK"; })
.subscribeOn(Schedulers.boundedElastic())
.timeout(Duration.ofSeconds(1))
.block(); // TimeoutException after ~1003 ms
Expected behavior
Each sync try fails with a timeout after tryTimeout and is retried, the same as on the async client.
Possible fix
Run the blocking call off the subscribing thread (for example subscribeOn(Schedulers.boundedElastic())), or enforce the timeout with an executor and Future.get(timeout). If changing this is not desirable, documenting that tryTimeout does not apply to sync clients would help.
Workaround
Set connect, response and read timeouts on the HTTP client (NettyAsyncHttpClientBuilder) and pass it with .httpClient(...), or use the async client.
Setup
- OS: Ubuntu 20.04 (x86_64)
- Library/Libraries: azure-storage-blob 12.36.0, azure-storage-common 12.35.0, azure-core 1.60.0, azure-core-http-netty 1.16.8, reactor-core 3.7.19, reactor-netty-http 1.2.18. The code in
RequestRetryPolicy.attemptSyncis unchanged onmain. - Java version: 25 (GraalVM 25.0.4)
- Frameworks: none
Information Checklist
- Bug Description Added
- Repro Steps Added
- Setup information Added
- 主要言語
- Java
- スター
- 2.6k
- フォーク
- 2.2k
- 平均マージ
- 2日 2時間
- マージ済み PR(30日)
- 257
環境構築
このプロジェクトの開発コンテナを、あなたの GitHub アカウントでブラウザ上に起動します。
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートあり
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
Azure/azure-sdk-for-java のほかの issue
-
[Spring Cloud Azure] Improve Javadoc and startup guidance for allowed-group-names vs allowed-group-ids in AadAuthenticationProperties対応中かも @himanchalkaushale が 7 日前に担当しました。 オープンazure-spring azure-spring-aad Client
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
Azure/azure-sdk-for-java#51046 · コメント 2 件 · リアクション 1 件 ·
メンテナーはふだん 1 日以内に返信
-
mgmt, in track 1 migration guide, call out that file-based authentication method is not recommended再び着手できるかも このイシューのプルリクエストはマージされずにクローズされました。 オープンAzure.Identity
難易度 1/5 1時間未満 初心者へのやさしさ 74/100
Azure/azure-sdk-for-java#48894 ·
メンテナーはふだん 1 日以内に返信
-
[BUG] DataLakeFileSystemAsyncClient.createIfNotExists returns true when the file system already exists対応中かも @browndav-msft が今日担当しました。 オープンClient customer-reported needs-team-attention question Storage
Azure/azure-sdk-for-java#51145 · コメント 2 件 · リアクション 1 件 · 担当者 2 名 ·
メンテナーはふだん 1 日以内に返信
-
Client Cosmos
難易度 3/5 1〜2日 初心者へのやさしさ 68/100
Azure/azure-sdk-for-java#51134 · リアクション 1 件 ·
メンテナーはふだん 1 日以内に返信
-
Client Cosmos
難易度 4/5 3〜5日 初心者へのやさしさ 45/100
Azure/azure-sdk-for-java#51133 · リアクション 1 件 ·
メンテナーはふだん 1 日以内に返信
Azure/azure-sdk-for-java の issue をすべて見る
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 80/100
googleads/googleads-mobile-flutter#1541 ·
メンテナーはふだん 4 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 73/100
Julow/Unexpected-Keyboard#1490 ·
メンテナーはふだん 4 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 67/100
Vakore/ZappierGames#275 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
unitycatalog/unitycatalog#2148 ·
メンテナーはふだん 2 日以内に返信
-
enhancement priority: low
難易度 1/5 1時間未満 初心者へのやさしさ 92/100
Riptide-Labs/riptide#1060 ·
メンテナーはふだん 1 日以内に返信