Spring-Boot WebClient block() method returns error java.lang.IllegalStateException - spring-boot

I'm trying to fetch value(string) using Spring WebFlux WebClient, (Using SpringBoot version 2.4.5,)
#GetMapping("/test")
public Mono<String> getData(){
WebClient webClient = WebClient.create("http://localhost:9999");
Mono<String> stringMono = webClient.get()
.uri("/some/thing")
.retrieve()
.bodyToMono(String.class);
stringMono.subscribe( System.out::println);
System.out.println("Value : " + stringMono.block()); // this doesn't work, expecting to return ResponseBody as "Hello World" ,
return stringMono;
}
But getting below error
2021-05-11 20:02:15.521 ERROR 55613 --- [ctor-http-nio-2] a.w.r.e.AbstractErrorWebExceptionHandler : [19114471-1] 500 Server Error for HTTP GET "/test"
java.lang.IllegalStateException: block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-2
at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:83) ~[reactor-core-3.4.3.jar:3.4.3]
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
|_ checkpoint ⇢ HTTP GET "/test" [ExceptionHandlingWebHandler]
Stack trace:
at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:83) ~[reactor-core-3.4.3.jar:3.4.3]
at reactor.core.publisher.Mono.block(Mono.java:1703) ~[reactor-core-3.4.3.jar:3.4.3]
at com.example.demo.DemoApplication.getData(DemoApplication.java:28) ~[main/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.springframework.web.reactive.result.method.InvocableHandlerMethod.lambda$invoke$0(InvocableHandlerMethod.java:146) ~[spring-webflux-5.3.4.jar:5.3.4]
at reactor.core.publisher.FluxFlatMap.trySubscribeScalarMap(FluxFlatMap.java:151) ~[reactor-core-3.4.3.jar:3.4.3]
Reference for block method - https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#webflux-client-synchronous

When using Webflux, the whole idea is that you don't block - you'll cause massive performance problems if you do (see here for a related answer that explains why) so the framework explicitly disallows it, throwing an exception if you try.
You also shouldn't subscribe manually - while not a "mortal sin" in the reactive world as blocking is, that's certainly another red flag. Subscription is handled by the framework. You just need to return the Mono, and Webflux will subscribe when required to handle your request. In your case your manual subscription means the entire chain will actually be executed twice for each request - once to print the result out to the terminal, and once to return the result to the /test endpoint.
Instead, if you want a "side-effect" like this (printing out the value when you have it) then you need to alter the reactive chain to do so, using the doOnNext() operator. This means you can then do:
return webClient.get()
.uri("/some/thing")
.retrieve()
.bodyToMono(String.class)
.doOnNext(s -> System.out.println("Value: " + s));
This will ensure the value is printed out to the terminal, but without blocking, and without manually subscribing.

Related

Pass through SOAP proxy spring Unsupported media type multipart/related; type="application/xop+xml"; boundary

Hi I am trying to implement a pass through SOAP proxy via #RestController in spring. For this purpose I have mapped a rest controller in following way:
#RestController
class MyProxy {
#PostMapping(value = "/**")
public ResponseEntity<String> proxyPost(#RequestBody(required = false) String body, HttpServletRequest request) {}
}
The regular SOAP requests are going OK. The problem comes when a MTOM type of SOAP request is send via the proxy. Then spring failes with unrecognized content type. Here is the exception:
Caused by: org.springframework.web.multipart.MultipartException: Failed to parse multipart servlet request; nested exception is javax.servlet.ServletException: Unsupported Content-Type [multipart/related; type="application/xop+xml"; boundary="uuid:dacf4733-80b4-41bc-b2e1-db69b6beadf6"; start="<root.message#cxf.apache.org>"; start-info="text/xml"], expected [multipart/form-data]
at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.handleParseFailure(StandardMultipartHttpServletRequest.java:124)
at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.parseRequest(StandardMultipartHttpServletRequest.java:115)
at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.<init>(StandardMultipartHttpServletRequest.java:88)
at org.springframework.web.multipart.support.StandardServletMultipartResolver.resolveMultipart(StandardServletMultipartResolver.java:122)
at org.springframework.web.servlet.DispatcherServlet.checkMultipart(DispatcherServlet.java:1205)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1039)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
... 60 common frames omitted
Caused by: javax.servlet.ServletException: Unsupported Content-Type [multipart/related; type="application/xop+xml"; boundary="uuid:dacf4733-80b4-41bc-b2e1-db69b6beadf6"; start="<root.message#cxf.apache.org>"; start-info="text/xml"], expected [multipart/form-data]
at org.eclipse.jetty.server.Request.getParts(Request.java:2407)
at javax.servlet.http.HttpServletRequestWrapper.getParts(HttpServletRequestWrapper.java:317)
at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.parseRequest(StandardMultipartHttpServletRequest.java:95)
... 66 common frames omitted
When receiving a multipart/* request Spring delegates this to the configured Multipart handler. This is enabled by default and for this case should be disabled.
spring.servlet.multipart.enabled=false
Adding the above to your properties should disable it and prevent the parsing, so you can handle it in your controller.

SpringBoot Camel (3.14.0) and ElasticSearch Integration

I'm trying to integrate Spring Boot (2.6.3) with Camel (3.14.0) to send a simple query to ElasticSearch.
The project is located at https://github.com/saavedrah/springboot-camel-elastic
I have a timer that sends a ElasticSearch query every 60 sec.
However, the following exception is generated:
2022-01-26 11:08:48.036 WARN 23668 --- [1 - timer://foo] o.a.camel.component.timer.TimerConsumer : Error processing exchange. Exchange[2578AAA06ED30CB-0000000000000000]. Caused by: [org.apache.camel.CamelExecutionException - Exception occurred during execution on the exchange: Exchange[]]
org.apache.camel.CamelExecutionException: Exception occurred during execution on the exchange: Exchange[]
at org.apache.camel.CamelExecutionException.wrapCamelExecutionException(CamelExecutionException.java:45) ~[camel-api-3.14.0.jar:3.14.0]
at org.apache.camel.support.AbstractExchange.setException(AbstractExchange.java:589) ~[camel-support-3.14.0.jar:3.14.0]
at org.apache.camel.support.DefaultExchange.setException(DefaultExchange.java:27) ~[camel-support-3.14.0.jar:3.14.0]
at org.apache.camel.support.AsyncProcessorConverterHelper$ProcessorToAsyncProcessorBridge.process(AsyncProcessorConverterHelper.java:69) ~[camel-support-3.14.0.jar:3.14.0]
at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:172) ~[camel-core-processor-3.14.0.jar:3.14.0]
at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$SimpleTask.run(RedeliveryErrorHandler.java:469) ~[camel-core-processor-3.14.0.jar:3.14.0]
at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:187) ~[camel-base-engine-3.14.0.jar:3.14.0]
at org.apache.camel.impl.engine.DefaultReactiveExecutor.scheduleMain(DefaultReactiveExecutor.java:64) ~[camel-base-engine-3.14.0.jar:3.14.0]
at org.apache.camel.processor.Pipeline.process(Pipeline.java:184) ~[camel-core-processor-3.14.0.jar:3.14.0]
at org.apache.camel.impl.engine.CamelInternalProcessor.process(CamelInternalProcessor.java:398) ~[camel-base-engine-3.14.0.jar:3.14.0]
at org.apache.camel.component.timer.TimerConsumer.sendTimerExchange(TimerConsumer.java:210) ~[camel-timer-3.14.0.jar:3.14.0]
at org.apache.camel.component.timer.TimerConsumer$1.run(TimerConsumer.java:76) ~[camel-timer-3.14.0.jar:3.14.0]
at java.base/java.util.TimerThread.mainLoop(Timer.java:556) ~[na:na]
at java.base/java.util.TimerThread.run(Timer.java:506) ~[na:na]
Caused by: java.lang.NoClassDefFoundError: org/elasticsearch/common/CheckedConsumer
at org.apache.camel.component.elasticsearch.ElasticsearchProducer$HighLevelClient.<init>(ElasticsearchProducer.java:347) ~[camel-elasticsearch-rest-3.14.0.jar:3.14.0]
at org.apache.camel.component.elasticsearch.ElasticsearchProducer$HighLevelClient.<init>(ElasticsearchProducer.java:345) ~[camel-elasticsearch-rest-3.14.0.jar:3.14.0]
at org.apache.camel.component.elasticsearch.ElasticsearchProducer.process(ElasticsearchProducer.java:124) ~[camel-elasticsearch-rest-3.14.0.jar:3.14.0]
at org.apache.camel.support.AsyncProcessorConverterHelper$ProcessorToAsyncProcessorBridge.process(AsyncProcessorConverterHelper.java:66) ~[camel-support-3.14.0.jar:3.14.0]
... 10 common frames omitted
Caused by: java.lang.ClassNotFoundException: org.elasticsearch.common.CheckedConsumer
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581) ~[na:na]
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178) ~[na:na]
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521) ~[na:na]
... 14 common frames omitted
UPDATE 1
Accordingly with this site CAMEL-17183 the downloaded version of ElasticSearch (7.15.2) does not have the [org.elasticsearch.common.CheckedConsumer] class.
So, how should I update the gradle.properties to get the supported version of ElasticSearch(7.8.0) ?
UPDATE 2
Gradle properties was updated to force the version of ElasticSearch.
configurations.all {
resolutionStrategy {
dependencySubstitution {
substitute module('org.elasticsearch.client:elasticsearch-rest-high-level-client') with module('org.elasticsearch.client:elasticsearch-rest-high-level-client:7.8.0')
substitute module('org.elasticsearch.client:elasticsearch-rest-client') with module('org.elasticsearch.client:elasticsearch-rest-client:7.8.0')
substitute module('org.elasticsearch:elasticsearch') with module('org.elasticsearch:elasticsearch:7.8.0')
}
}
}
And now I'm getting the following exception, I guess it is related with the lack of parameters passed to the query...
java.lang.IllegalArgumentException: Wrong body type. Only Map, String or SearchRequest is allowed as a type
at org.apache.camel.component.elasticsearch.ElasticsearchProducer.process(ElasticsearchProducer.java:232)
at org.apache.camel.support.AsyncProcessorConverterHelper$ProcessorToAsyncProcessorBridge.process(AsyncProcessorConverterHelper.java:66)
at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:172)
at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$SimpleTask.run(RedeliveryErrorHandler.java:469)
at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:187)
at org.apache.camel.impl.engine.DefaultReactiveExecutor.scheduleMain(DefaultReactiveExecutor.java:64)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:184)
at org.apache.camel.impl.engine.CamelInternalProcessor.process(CamelInternalProcessor.java:398)
at org.apache.camel.component.timer.TimerConsumer.sendTimerExchange(TimerConsumer.java:210)
at org.apache.camel.component.timer.TimerConsumer$1.run(TimerConsumer.java:76)
at java.base/java.util.TimerThread.mainLoop(Timer.java:556)
at java.base/java.util.TimerThread.run(Timer.java:506)
13:13:25.219 [Camel (camel-1) thread #1 - timer://foo] WARN o.a.c.component.timer.TimerConsumer - Error processing exchange. Exchange[DB28E010007B18C-0000000000000006]. Caused by: [java.lang.IllegalArgumentException - Wrong body type. Only Map, String or SearchRequest is allowed as a type]
java.lang.IllegalArgumentException: Wrong body type. Only Map, String or SearchRequest is allowed as a type
at org.apache.camel.component.elasticsearch.ElasticsearchProducer.process(ElasticsearchProducer.java:232)
at org.apache.camel.support.AsyncProcessorConverterHelper$ProcessorToAsyncProcessorBridge.process(AsyncProcessorConverterHelper.java:66)
at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:172)
at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$SimpleTask.run(RedeliveryErrorHandler.java:469)
at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:187)
at org.apache.camel.impl.engine.DefaultReactiveExecutor.scheduleMain(DefaultReactiveExecutor.java:64)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:184)
at org.apache.camel.impl.engine.CamelInternalProcessor.process(CamelInternalProcessor.java:398)
at org.apache.camel.component.timer.TimerConsumer.sendTimerExchange(TimerConsumer.java:210)
at org.apache.camel.component.timer.TimerConsumer$1.run(TimerConsumer.java:76)
at java.base/java.util.TimerThread.mainLoop(Timer.java:556)
at java.base/java.util.TimerThread.run(Timer.java:506)
Any help is appreciated.
What Huang was telling me was that I should put some query in my timer component body to pass it to the Search operation, something like:
from("timer://foo?fixedRate=true&period=60000")
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
exchange.getIn().setBody("{\"query\":{\"match_all\":{}}}");
}
})
.to("direct:search");
from("direct:search")
.to("elasticsearch-rest://elasticsearch?operation=Search&indexName=twitter");
Thank you.

Kotlin based Spring RabbitListener produces endlessloop trying to send back `kotlin.Unit`

We have a RabbitListener implemented in Kotlin. The method returns Unit, so I dont expect Spring to send a result but we are getting the following error message. It looks like Spring tries to iterprete Unit as the result and send a rabbit message back:
2021-04-16 16:39:21
msg="Execution of Rabbit message listener failed." thread="org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-2" level=WARN logger="org.springframework.amqp.rabbit.listener.ConditionalRejectingErrorHandler" exception="org.springframework.amqp.rabbit.support.ListenerExecutionFailedException: Listener threw exception
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.wrapToListenerExecutionFailedExceptionIfNeeded(AbstractMessageListenerContainer.java:1746)
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:1636)
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.actualInvokeListener(AbstractMessageListenerContainer.java:1551)
at jdk.internal.reflect.GeneratedMethodAccessor64.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at brave.spring.rabbit.TracingRabbitListenerAdvice.invoke(TracingRabbitListenerAdvice.java:108)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)
at org.springframework.amqp.rabbit.listener.$Proxy146.invokeListener(Unknown Source)
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:1539)
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:1530)
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:1474)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:967)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:913)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$1600(SimpleMessageListenerContainer.java:83)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.mainLoop(SimpleMessageListenerContainer.java:1288)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1194)
at java.base/java.lang.Thread.run(Unknown Source)
Caused by: org.springframework.amqp.rabbit.listener.adapter.ReplyFailureException: Failed to send reply with payload 'InvocationResult [returnValue=kotlin.Unit, returnType=class java.lang.Object, bean=com.xxx.EventHandler#4aaf6902, method=public java.lang.Object com.xxx.EventHandler.receiveMessage(org.springframework.amqp.core.Message)]'
at org.springframework.amqp.rabbit.listener.adapter.AbstractAdaptableMessageListener.doHandleResult(AbstractAdaptableMessageListener.java:476)
at org.springframework.amqp.rabbit.listener.adapter.AbstractAdaptableMessageListener.handleResult(AbstractAdaptableMessageListener.java:400)
at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.invokeHandlerAndProcessResult(MessagingMessageListenerAdapter.java:152)
at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.onMessage(MessagingMessageListenerAdapter.java:135)
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:1632)
... 20 common frames omitted
Caused by: java.lang.IllegalArgumentException: SimpleMessageConverter only supports String, byte[] and Serializable payloads, received: kotlin.Unit
at org.springframework.amqp.support.converter.SimpleMessageConverter.createMessage(SimpleMessageConverter.java:164)
at org.springframework.amqp.support.converter.AbstractMessageConverter.createMessage(AbstractMessageConverter.java:88)
at org.springframework.amqp.support.converter.AbstractMessageConverter.toMessage(AbstractMessageConverter.java:70)
at org.springframework.amqp.rabbit.listener.adapter.AbstractAdaptableMessageListener.convert(AbstractAdaptableMessageListener.java:519)
at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.buildMessage(MessagingMessageListenerAdapter.java:257)
at org.springframework.amqp.rabbit.listener.adapter.AbstractAdaptableMessageListener.doHandleResult(AbstractAdaptableMessageListener.java:464)
... 24 common frames omitted
" time="2021-04-16 14:39:21,726"
here a simplified version of the RabbitLister:
#Component
class EventHandler {
#RabbitListener(queues = ["someQueue"])
fun receiveMessage(message: Message): Unit {
log.debug("Received message")
}
}
We use Spring Boot 2.4.4, Spring Rabbit 2.3.6 and Spring Framework 5.3.6
debugging the issue, I got the following result:
What version are you using?
This works fine for me (with and without the Unit return type)...
#RabbitListener(queues = ["foo"])
open fun listen(data: String?): Unit {
println(data)
}
Even with : Unit, I see void as the return type and null:

Workaround for the slowness of the WebClient first request

I am using WebClient in a Spring Boot MVC 2.1 project and found that the first request made by the client takes up to 6 seconds. Subsequent requests are way faster (~30ms).
There's a closed issue in Spring's JIRA that advices using Jetty as the WebClient Http connector. I have tried that approach, improving the figures, with a ~800ms first request. This time is an improvement but it's still far from RestTemplate which usally takes <200ms.
Netty approach (5s first request):
Conf:
#Bean
public WebClient webClient() {
return WebClient.create();
}
Usage:
private final WebClient webClient;
#GetMapping(value="/wc", produces = APPLICATION_JSON_UTF8_VALUE)
public Mono<String> findWc() throws URISyntaxException {
URI uri = new URI("http://xxx");
final Mono<String> response = webClient.get().uri(uri).retrieve().bodyToMono(String.class);
return response;
}
Jetty approach (800ms first request):
Conf:
#Bean
public JettyResourceFactory resourceFactory() {
return new JettyResourceFactory();
}
#Bean
public WebClient webClient() {
ClientHttpConnector connector = new JettyClientHttpConnector(resourceFactory(), null);
return WebClient.builder().clientConnector(connector).build();
}
Usage: same as before.
There's another "problem" with the Jetty approach. On server shutdown it always produces the following exception:
27-Dec-2018 11:24:20.463 INFO [jetty-http#74305db9-65] org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading Illegal access: this web application instance has been stopped already. Could not load [org.eclipse.jetty.io.ManagedSelector$StopSelector]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
java.lang.IllegalStateException: Illegal access: this web application instance has been stopped already. Could not load [org.eclipse.jetty.io.ManagedSelector$StopSelector]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading(WebappClassLoaderBase.java:1348)
at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForClassLoading(WebappClassLoaderBase.java:1336)
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1195)
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1157)
at java.lang.Class.getDeclaringClass0(Native Method)
at java.lang.Class.getDeclaringClass(Class.java:1235)
at java.lang.Class.getEnclosingClass(Class.java:1277)
at java.lang.Class.getSimpleBinaryName(Class.java:1443)
at java.lang.Class.getSimpleName(Class.java:1309)
at org.eclipse.jetty.io.ManagedSelector$SelectorProducer.toString(ManagedSelector.java:534)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.getString(EatWhatYouKill.java:458)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.toStringLocked(EatWhatYouKill.java:447)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.toString(EatWhatYouKill.java:440)
at org.slf4j.helpers.MessageFormatter.safeObjectAppend(MessageFormatter.java:299)
at org.slf4j.helpers.MessageFormatter.deeplyAppendParameter(MessageFormatter.java:271)
at org.slf4j.helpers.MessageFormatter.arrayFormat(MessageFormatter.java:233)
at org.slf4j.helpers.MessageFormatter.arrayFormat(MessageFormatter.java:173)
at org.eclipse.jetty.util.log.JettyAwareLogger.log(JettyAwareLogger.java:680)
at org.eclipse.jetty.util.log.JettyAwareLogger.debug(JettyAwareLogger.java:224)
at org.eclipse.jetty.util.log.Slf4jLog.debug(Slf4jLog.java:97)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:288)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:168)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:126)
at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:366)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:765)
at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:683)
at java.lang.Thread.run(Thread.java:748)
SLF4J: Failed toString() invocation on an object of type [org.eclipse.jetty.util.thread.strategy.EatWhatYouKill]
Reported exception:
java.lang.NoClassDefFoundError: org/eclipse/jetty/io/ManagedSelector$StopSelector
at java.lang.Class.getDeclaringClass0(Native Method)
at java.lang.Class.getDeclaringClass(Class.java:1235)
at java.lang.Class.getEnclosingClass(Class.java:1277)
at java.lang.Class.getSimpleBinaryName(Class.java:1443)
at java.lang.Class.getSimpleName(Class.java:1309)
at org.eclipse.jetty.io.ManagedSelector$SelectorProducer.toString(ManagedSelector.java:534)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.getString(EatWhatYouKill.java:458)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.toStringLocked(EatWhatYouKill.java:447)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.toString(EatWhatYouKill.java:440)
at org.slf4j.helpers.MessageFormatter.safeObjectAppend(MessageFormatter.java:299)
at org.slf4j.helpers.MessageFormatter.deeplyAppendParameter(MessageFormatter.java:271)
at org.slf4j.helpers.MessageFormatter.arrayFormat(MessageFormatter.java:233)
at org.slf4j.helpers.MessageFormatter.arrayFormat(MessageFormatter.java:173)
at org.eclipse.jetty.util.log.JettyAwareLogger.log(JettyAwareLogger.java:680)
at org.eclipse.jetty.util.log.JettyAwareLogger.debug(JettyAwareLogger.java:224)
at org.eclipse.jetty.util.log.Slf4jLog.debug(Slf4jLog.java:97)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:288)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:168)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:126)
at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:366)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:765)
at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:683)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.ClassNotFoundException: Illegal access: this web application instance has been stopped already. Could not load [org.eclipse.jetty.io.ManagedSelector$StopSelector]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForClassLoading(WebappClassLoaderBase.java:1338)
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1195)
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1157)
... 25 more
Caused by: java.lang.IllegalStateException: Illegal access: this web application instance has been stopped already. Could not load [org.eclipse.jetty.io.ManagedSelector$StopSelector]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading(WebappClassLoaderBase.java:1348)
at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForClassLoading(WebappClassLoaderBase.java:1336)
... 27 more
27-Dec-2018 11:24:20.467 INFO [jetty-http#74305db9-65] org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading Illegal access: this web application instance has been stopped already. Could not load [ch.qos.logback.classic.spi.ThrowableProxy]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
java.lang.IllegalStateException: Illegal access: this web application instance has been stopped already. Could not load [ch.qos.logback.classic.spi.ThrowableProxy]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading(WebappClassLoaderBase.java:1348)
at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForClassLoading(WebappClassLoaderBase.java:1336)
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1195)
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1157)
at ch.qos.logback.classic.spi.LoggingEvent.<init>(LoggingEvent.java:119)
at ch.qos.logback.classic.Logger.buildLoggingEventAndAppend(Logger.java:419)
at ch.qos.logback.classic.Logger.filterAndLog_0_Or3Plus(Logger.java:383)
at ch.qos.logback.classic.Logger.log(Logger.java:765)
at org.eclipse.jetty.util.log.JettyAwareLogger.log(JettyAwareLogger.java:668)
at org.eclipse.jetty.util.log.JettyAwareLogger.warn(JettyAwareLogger.java:474)
at org.eclipse.jetty.util.log.Slf4jLog.warn(Slf4jLog.java:73)
at org.eclipse.jetty.util.log.Slf4jLog.warn(Slf4jLog.java:67)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.execute(EatWhatYouKill.java:375)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:305)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:168)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:126)
at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:366)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:765)
at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:683)
at java.lang.Thread.run(Thread.java:748)
Exception in thread "jetty-http#74305db9-65" java.lang.NoClassDefFoundError: ch/qos/logback/classic/spi/ThrowableProxy
at ch.qos.logback.classic.spi.LoggingEvent.<init>(LoggingEvent.java:119)
at ch.qos.logback.classic.Logger.buildLoggingEventAndAppend(Logger.java:419)
at ch.qos.logback.classic.Logger.filterAndLog_0_Or3Plus(Logger.java:383)
at ch.qos.logback.classic.Logger.log(Logger.java:765)
at org.eclipse.jetty.util.log.JettyAwareLogger.log(JettyAwareLogger.java:668)
at org.eclipse.jetty.util.log.JettyAwareLogger.warn(JettyAwareLogger.java:474)
at org.eclipse.jetty.util.log.Slf4jLog.warn(Slf4jLog.java:73)
at org.eclipse.jetty.util.log.Slf4jLog.warn(Slf4jLog.java:67)
at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:740)
at java.lang.Thread.run(Thread.java:748)
How can I avoid this exception?
Is there any other way we can use to improve the WebClient first request slowness?
I went through the same problem and managed to solve it by changing the connector used by the WebClient.
Below the configuration file with the appropriate imports
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.reactive.ClientHttpConnector;
import org.springframework.http.client.reactive.JettyClientHttpConnector;
import org.springframework.web.reactive.function.client.WebClient;
The class
SslContextFactory.Client sslContextFactory = new SslContextFactory.Client();
HttpClient httpClient = new HttpClient(sslContextFactory);
httpClient.setFollowRedirects(false);
httpClient.setConnectTimeout(TIMEOUT);
httpClient.start();
final ClientHttpConnector connector = new JettyClientHttpConnector(httpClient);
final WebClient webClient = WebClient.builder()
.clientConnector(connector)
.baseUrl(BASE_URL)
.build();
It is important to know how to add the right libs to your project, so below is how I managed to import using gradle:
implementation 'org.eclipse.jetty:jetty-client'
implementation 'org.eclipse.jetty:jetty-reactive-httpclient'
We upgraded Spring Boot to 2.4.2 with reactor-netty 1.0.3 but still encounter this issue.
Here is our upgraded configuration:
#Bean
public WebClient createWebClient(WebClient.Builder webClientBuilder) {
log.info("Initializing WebClient Bean");
final int timeoutInMillis = Long.valueOf(TimeUnit.SECONDS.toMillis(timeout)).intValue();
final HttpClient httpClient = HttpClient.create()
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, timeoutInMillis)
.responseTimeout(Duration.ofMillis(timeoutInMillis))
.doOnConnected(conn ->
conn.addHandlerLast(new ReadTimeoutHandler(timeoutInMillis, TimeUnit.MILLISECONDS))
.addHandlerLast(new WriteTimeoutHandler(timeoutInMillis, TimeUnit.MILLISECONDS)));
final ClientHttpConnector connector = new ReactorClientHttpConnector(httpClient);
final WebClient webClient = webClientBuilder
.clientConnector(connector)
.defaultHeader("x-clientname", clientname)
.build();
httpClient.warmup().block();
log.info("WebClient initialized");
return webClient;
}
Our call with WebClient:
ResoponseObject doCall() {
return this.webClient
.get()
.uri("http://***.de/api/rest/***")
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(ResponseObject.class)
.block();
}
With debugging enabled via application.yaml:
logging.level.reactor.netty: debug
We now see this during application startup:
2021-02-10 17:02:31,922 INFO d.t.e.b.c.c.WebClientAutoConfiguration - Initializing WebClient Bean
2021-02-10 17:02:31,959 DEBUG r.n.r.DefaultLoopIOUring - Default io_uring support : false
2021-02-10 17:02:31,967 DEBUG r.n.r.DefaultLoopEpoll - Default Epoll support : true
2021-02-10 17:02:31,997 INFO d.t.e.b.c.c.WebClientAutoConfiguration - WebClient initialized
This should be an indication that the warmup works as expected?
But on first request this happens:
2021-02-10 17:05:16,045 DEBUG o.s.w.r.f.c.ExchangeFunctions - [73d400c8] HTTP GET http://***.de/api/rest/***
2021-02-10 17:05:16,050 DEBUG r.n.r.PooledConnectionProvider - Creating a new [http] client pool [PoolFactory{evictionInterval=PT0S, leasingStrategy=fifo, maxConnections=500, maxIdleTime=-1, maxLifeTime=-1, metricsEnabled=false, pendingAcquireMaxCount=1000, pendingAcquireTimeout=45000}] for [***.de/<unresolved>:80]
2021-02-10 17:05:29,619 DEBUG r.n.r.DefaultPooledConnectionProvider - [id: 0x71b840f4] Created a new pooled channel, now 1 active connections and 0 inactive connections
2021-02-10 17:05:29,635 DEBUG r.n.t.TransportConfig - [id: 0x71b840f4] Initialized pipeline DefaultChannelPipeline{(reactor.left.httpCodec = io.netty.handler.codec.http.HttpClientCodec), (reactor.right.reactiveBridge = reactor.netty.channel.ChannelOperationsHandler)}
...
In our case, creating the client pool is the problem. On a decent machine, it takes about 13 seconds.
Can you give us any comment on that? This is very this is very frustrating for us.
Thanks a lot!

How do i resolve this : javax.ws.rs.NotFoundException: HTTP 404 Resource_not_found

I was trying to get familier with JAX-RS and here is my code sniplets
WebTarget target; // this object reference was created successfully
public Client[] getClients() {
return target.request().get(Client[].class); // NOTE target is not null
}
This is the exception which is logged
Caused by: javax.ws.rs.NotFoundException: HTTP 404 Resource_not_found
at org.glassfish.jersey.client.JerseyInvocation.convertToException(JerseyInvocation.java:945)
at org.glassfish.jersey.client.JerseyInvocation.translate(JerseyInvocation.java:784)
at org.glassfish.jersey.client.JerseyInvocation.access$500(JerseyInvocation.java:91)
at org.glassfish.jersey.client.JerseyInvocation$2.call(JerseyInvocation.java:672)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:228)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:424)
at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:668)
at org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:397)
at org.glassfish.jersey.client.JerseyInvocation$Builder.get(JerseyInvocation.java:297)
at org.business.bee.client.ClientBean.getClients(ClientBean.java:67)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
If an error is thrown in a getter you'll get the _"FATAL: JSF1073: javax.el.ELException caught during processing of RENDER_RESPONSE 6"_ or similar. The underlying (real!) error has nothing to do with jsf, ejb, jstl or facelets. Just make sure the following exception (thrown in your code trying to access a rest service) does not happen:
javax.ws.rs.NotFoundException: HTTP 404 Resource_not_found

Resources