Skip to content

AzurePipelinesCredential does async over sync (over async) causing problems in AMQP tests #44519

Open

Description

AMQP has a specific threading model and gets token on a thread that can't be blocked. It uses async getToken API.
In the case of AzurePipelinesCredential this results in something like this

06 Mar 2025 02:34:28,193 [reactor-executor-1] ERROR com.azure.core.http.netty.NettyAsyncHttpClient - block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-executor-1
java.lang.IllegalStateException: block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-executor-1
	at reactor.core@3.4.41/reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:83)
	at reactor.core@3.4.41/reactor.core.publisher.Mono.block(Mono.java:1742)
	at com.azure.http.netty@1.15.10/com.azure.core.http.netty.NettyAsyncHttpClient.sendSync(NettyAsyncHttpClient.java:195)
	at com.azure.core@1.55.2/com.azure.core.http.HttpPipelineNextSyncPolicy.processSync(HttpPipelineNextSyncPolicy.java:51)
	at com.azure.core@1.55.2/com.azure.core.http.policy.HttpLoggingPolicy.processSync(HttpLoggingPolicy.java:175)
	at com.azure.core@1.55.2/com.azure.core.http.HttpPipelineNextSyncPolicy.processSync(HttpPipelineNextSyncPolicy.java:53)
	at com.azure.core@1.55.2/com.azure.core.implementation.http.policy.InstrumentationPolicy.processSync(InstrumentationPolicy.java:101)
	at com.azure.core@1.55.2/com.azure.core.http.HttpPipelineNextSyncPolicy.processSync(HttpPipelineNextSyncPolicy.java:53)
	at com.azure.core@1.55.2/com.azure.core.http.policy.RetryPolicy.attemptSync(RetryPolicy.java:217)
	at com.azure.core@1.55.2/com.azure.core.http.policy.RetryPolicy.processSync(RetryPolicy.java:161)
	at com.azure.core@1.55.2/com.azure.core.http.HttpPipelineNextSyncPolicy.processSync(HttpPipelineNextSyncPolicy.java:53)
	at com.azure.core@1.55.2/com.azure.core.http.policy.AddHeadersPolicy.processSync(AddHeadersPolicy.java:66)
	at com.azure.core@1.55.2/com.azure.core.http.HttpPipelineNextSyncPolicy.processSync(HttpPipelineNextSyncPolicy.java:53)
	at com.azure.core@1.55.2/com.azure.core.http.policy.HttpPipelineSyncPolicy.processSync(HttpPipelineSyncPolicy.java:51)
	at com.azure.core@1.55.2/com.azure.core.http.policy.UserAgentPolicy.processSync(UserAgentPolicy.java:174)
	at com.azure.core@1.55.2/com.azure.core.http.HttpPipelineNextSyncPolicy.processSync(HttpPipelineNextSyncPolicy.java:53)
	at com.azure.core@1.55.2/com.azure.core.http.HttpPipeline.sendSync(HttpPipeline.java:138)
	at com.azure.identity.AzurePipelinesCredential.lambda$new$0(AzurePipelinesCredential.java:80)
	at com.azure.identity.implementation.IdentityClientBase.getConfidentialClient(IdentityClientBase.java:232)
	at com.azure.identity.implementation.IdentityClient.lambda$getConfidentialClientApplication$5(IdentityClient.java:152)
	at reactor.core@3.4.41/reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:45)
	at reactor.core@3.4.41/reactor.core.publisher.MonoCacheTime.subscribeOrReturn(MonoCacheTime.java:143)
	at reactor.core@3.4.41/reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:57)
	at reactor.core@3.4.41/reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:157)
	at reactor.core@3.4.41/reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1839)
	at reactor.core@3.4.41/reactor.core.publisher.MonoCacheInvalidateIf$CoordinatorSubscriber.onNext(MonoCacheInvalidateIf.java:319)
	at reactor.core@3.4.41/reactor.core.publisher.FluxHandle$HandleSubscriber.onNext(FluxHandle.java:126)
	at reactor.core@3.4.41/reactor.core.publisher.SerializedSubscriber.onNext(SerializedSubscriber.java:99)
	at reactor.core@3.4.41/reactor.core.publisher.FluxRetryWhen$RetryWhenMainSubscriber.onNext(FluxRetryWhen.java:174)
	at reactor.core@3.4.41/reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1839)
	at reactor.core@3.4.41/reactor.core.publisher.MonoFlatMap$FlatMapInner.onNext(MonoFlatMap.java:249)
	at reactor.core@3.4.41/reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.complete(MonoIgnoreThen.java:292)
	at reactor.core@3.4.41/reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onNext(MonoIgnoreThen.java:187)
	at reactor.core@3.4.41/reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:236)
	at reactor.core@3.4.41/reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onComplete(MonoIgnoreThen.java:203)
	at reactor.core@3.4.41/reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:260)
	at reactor.core@3.4.41/reactor.core.publisher.SerializedSubscriber.onComplete(SerializedSubscriber.java:146)
	at reactor.core@3.4.41/reactor.core.publisher.FluxTimeout$TimeoutMainSubscriber.onComplete(FluxTimeout.java:234)
	at reactor.core@3.4.41/reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onComplete(FluxSwitchIfEmpty.java:85)
	at reactor.core@3.4.41/reactor.core.publisher.MonoNext$NextSubscriber.onComplete(MonoNext.java:102)
	at reactor.core@3.4.41/reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:83)
	at reactor.core@3.4.41/reactor.core.publisher.FluxFilter$FilterSubscriber.onNext(FluxFilter.java:113)
	at reactor.core@3.4.41/reactor.core.publisher.EmitterProcessor.drain(EmitterProcessor.java:537)
	at reactor.core@3.4.41/reactor.core.publisher.EmitterProcessor.tryEmitNext(EmitterProcessor.java:343)
	at reactor.core@3.4.41/reactor.core.publisher.SinkManySerialized.tryEmitNext(SinkManySerialized.java:100)
	at reactor.core@3.4.41/reactor.core.publisher.InternalManySink.emitNext(InternalManySink.java:27)
	at com.azure.core.amqp.implementation.RequestResponseChannel.updateEndpointState(RequestResponseChannel.java:496)

because of this code

try (HttpResponse response = httpPipeline.sendSync(request, Context.NONE)) {

that does sync over async (and back to async under because of Netty).

While this affects tests only, it'd be nice to avoid async over sync and minimize issues like this.

Activity

  1. github-actions commented on Mar 6, 2025

    @github-actions
    Contributor

    Thank you for your feedback. Tagging and routing to the team member best able to assist.

  2. lmolkova commented on Mar 6, 2025

    @lmolkova
    Author

    Based on offline discussion with Alan Zimmer (@alzimmermsft) and Anu Thomas (@anuchandy), AzurePipelineCredentials is used in production applications.
    Plus there is a reactor contract for Mono that underlying work should not block the caller/subscriber and recommendation to wrap blocking calls and execute them on bounded elastic scheduler - https://projectreactor.io/docs/core/release/reference/faq.html#faq.wrap-blocking

    So it's important to fix it for all possible users of AzurePipelineCredentials and either implement a fully async pipeline or follow https://projectreactor.io/docs/core/release/reference/faq.html#faq.wrap-blocking if that's impossible

  3. added
    bugThis issue requires a change to an existing behavior in the product in order to be resolved.
    on Mar 6, 2025
  4. added this to the Backlog milestone on Apr 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Azure.Coreazure-coreAzure.IdentityClientThis issue points to a problem in the data-plane of the library.bugThis issue requires a change to an existing behavior in the product in order to be resolved.needs-team-attentionWorkflow: This issue needs attention from Azure service team or SDK team

Type

No type

Projects

Relationships

None yet

Development

No branches or pull requests

Issue actions