micronaut-core: Micronaut Client slow, occasional ReadTimeoutException
Expected Behavior
I expected that using a Micronaut Http Client would return results at a similar speed as compared with using java.net.http.HttpClient
.
Actual Behaviour
Comparing side by side with a direct HttpClient GET request and a Micronaut Client request the micronaut client is consistently 3-4 times slower.
- Test Application
- java.net.http.HttpClient - 30-40 ms
- io.micronaut.http.client.annotation.Client - 90-100 ms
- Production Application
- java.net.http.HttpClient - 80-100 ms
- io.micronaut.http.client.annotation.Client - 400-500 ms
I also found that the micronaut client occasionally throws a read timeout exception after hanging for 10-20 seconds. On my aws fargate instance this happens quite often. On my local box it only happens once per 30-40 requests.
io.micronaut.http.client.exceptions.ReadTimeoutException: Read Timeout at io.micronaut.http.client.exceptions.ReadTimeoutException.<clinit>(ReadTimeoutException.java:26) at io.micronaut.http.client.netty.DefaultHttpClient.lambda$exchangeImpl$44(DefaultHttpClient.java:1378) at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:94) at io.micronaut.reactive.reactor.instrument.ReactorSubscriber.onError(ReactorSubscriber.java:64) at reactor.core.publisher.SerializedSubscriber.onError(SerializedSubscriber.java:124) at reactor.core.publisher.FluxTimeout$TimeoutMainSubscriber.handleTimeout(FluxTimeout.java:295) at reactor.core.publisher.FluxTimeout$TimeoutMainSubscriber.doTimeout(FluxTimeout.java:280) at reactor.core.publisher.FluxTimeout$TimeoutTimeoutSubscriber.onNext(FluxTimeout.java:419) at io.micronaut.reactive.reactor.instrument.ReactorSubscriber.onNext(ReactorSubscriber.java:57) at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79) at io.micronaut.reactive.reactor.instrument.ReactorSubscriber.onNext(ReactorSubscriber.java:57) at reactor.core.publisher.MonoDelay$MonoDelayRunnable.propagateDelay(MonoDelay.java:271) at reactor.core.publisher.MonoDelay$MonoDelayRunnable.run(MonoDelay.java:286) at io.micronaut.reactive.reactor.instrument.ReactorInstrumentation.lambda$init$0(ReactorInstrumentation.java:62) at reactor.core.scheduler.SchedulerTask.call(SchedulerTask.java:68) at reactor.core.scheduler.SchedulerTask.call(SchedulerTask.java:28) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) at java.base/java.lang.Thread.run(Thread.java:833)
Steps To Reproduce
- Checkout https://github.com/kevind-wgu/mn-client-test
- mvn clean install
- java -jar target/mn-0.1.jar
- curl “localhost:8080/book/direct” (run multiple times)
- curl “localhost:8080/book/micronaut” (run multiple times)
I have found the direct HttpClient takes about 30-40 ms to download, convert to Book object and return it. I have found the Micronaut Client takes about 100ms to download and return a string.
- I failed to get the micronaut client to convert the string to an object. I kept getting a
io.micronaut.http.codec.CodecException: Cannot decode bytes with value
and couldn’t figure out why so I gave up assuming that returning a String instead of a Book object should be faster anyway.
Environment Information
MacOS - Monterey, 12.5.1 Java - openjdk version “17.0.3” 2022-04-19 LTS Maven - Apache Maven 3.6.3
Example Application
https://github.com/kevind-wgu/mn-client-test
Version
3.6.0
About this issue
- Original URL
- State: open
- Created 2 years ago
- Reactions: 7
- Comments: 15 (5 by maintainers)
Can also confirm this is happening. I’m using the httpClient in a @Scheduled controller method. Have tried with a different event loop group and also using @ExecuteOn, neither prevented the read timeout and I have the client read timeout set to “30s” which is plenty for what I’m calling.
I made the changes recommended in the docs and it gets rid of the random ReadTimeout exceptions. It continues to be a little over twice as slow (80-100ms instead of 20-40). Maybe that is expected?
Here are the changes I made to application.yml
Can the Micronaut HttpClient be used in non-reactive style coding without blocking the event loop?
You’re blocking the event loop so that is the likely cause of the read timeouts