'Unsafe.park' taking too long When Blocking WebClient Calls in Spring Boot Application
Asked Answered
P

0

3

I am encountering an issue in my Spring Boot application where I am using WebClient to make synchronous calls to a remote service. However, when I use the block() method to wait for the WebClient response, I have observed that Unsafe.park takes too much time to execute and it keeps on increasing with subsequent calls. This occurs intermittently and seems to be related to thread contention or deadlock.In some cases, this Unsafe.park keeps on exceuting for more than 1 minute, causing significant delays in my application.

Here's a simplified version of my code:

Root uploadedFile = WebClient.builder().build().post().uri(uri)
        .contentType(MediaType.APPLICATION_JSON)
        .header("Authorization", apiKey)
        .body(BodyInserters.fromMultipartData(map))
        .retrieve()
        .bodyToMono(Root.class)
        .block(); // <-- Issue occurs here

enter image description here

The block() method seems to be causing the main thread to park indefinitely, resulting in the Unsafe.park issue. This problem occurs sporadically and is difficult to reproduce consistently.

Are there any known issues or best practices related to using block() with WebClient in Spring Boot applications? Any suggestions or insights on how to troubleshoot and resolve this issue would be greatly appreciated. Thank you!

Pseudohermaphroditism answered 5/4 at 11:25 Comment(10)
What is an Unsafe.park issue?Dune
Mono#block suggests it will wait indefinitely for the next signal from a resource. I'm not as familiar with reactor-core/mono, but perhaps it's possible you already have the "signal" received from your post request at the time of #retrieve, such that #block is simply waiting for another signal that will never arrive?Numbskull
So you have the issue that a method named block does block the thread but felt the need to invent the phrase “Unsafe.park issues” for the situation?Meddle
If you refer the screenshot with trace, you can see that unsafe park thread takes the most amount of time, and I have observed that if it the time is more for 1 call , it keeps on increasing for subsequent calls, so I just want to know whether there is a issue with my code or is the third party api at fault. @MeddlePseudohermaphroditism
park() is the backend of almost every method of the concurrency APIs that may block or wait for some time. Everything below blockingGet is an irrelevant implementation detail. You see that a method named blockingGet is blocking, which sounds like expected behavior given the name. Is it blocking too much or too long? Well, only you can tell. So far, you didn’t say that you have an actual performance or latency issue, only those “Unsafe.park issues”.Meddle
yes, we do have some performance issues. It is blocking too much and is not able to handle concurrent calls.Pseudohermaphroditism
In simple terms, does block() make the code synchronous or does it make the incoming requests synchronous thereby affecting the concurrency ? @MeddlePseudohermaphroditism
I don’t get your question. “synchronous” means “synchronous”. There aren’t different forms of “synchronous”.Meddle
If you're blocking, the thread you reside on is forced to wait until it is "unblocked" (usually by another thread). If that's your main application thread or a GUI thread, it can cause holdups. If it's a resource thread of some pool (e.g. some "async" processor or a thread pool), you can risk exhausting the available resources in the pool. I think Holger is interested in the measurable impact on your system as a result of this blocking. You mentioned using spring-boot, but your code snippet has no context, we don't know on which thread you're actually performing this blocking call.Numbskull
That said, you've noted that there is an impact regarding the blocking appearing to take longer and longer per block. Have you checked if the backend service you are POSTing to isn't suffering some performance bottleneck itself? How long does an independent POST request (outside this application) take during this test? Have you debugged this particular code after breaking up the call chain (e.g. instead of m.foo().bar(), you'd have n = m.foo(); n.bar();)?Numbskull

© 2022 - 2024 — McMap. All rights reserved.