I'm trying to improve the error handling in a controller by using the #Error annotation.
#Get(uri = "/{id}")
#Secured("ROLE_VIEW")
HttpResponse<AuthorResource> show(Long id) {
try {
ok(authorService.get(id).get())
} catch (Exception e) {
e.printStackTrace()
throw e
}
}
The get() method will either return the AuthorResource (io.vavr.control.Try), or throw a custom exception, subclass of our base ErrorContext exception class.
I then added the following errorhandler in the controller:
#Error(exception = ErrorContext, global = true)
HttpResponse<ErrorContext> onErrorContext(HttpRequest request, ErrorContext error) {
HttpResponse.<ErrorContext>status(HttpStatus.valueOf(error.code)).body(error)
}
Unfortunately, the exception handler does not seem to be invoked, and an INTERNAL_SERVER_ERROR is triggered (instead of a NOT_FOUND in this example). The output of the gradle test task can be found below.
I have tried the following:
Using a global handler (global=true)
Annotating the handler with the actual subclass that is being thrown (ErrorContextWithoutStacktrace)
Am I missing anything?
I have created a working application in github here
Controller class
Test class
Output of test (including partial stacktraces due to length limitation in SO):
10:50:31.455 [ForkJoinPool.commonPool-worker-7] INFO i.m.t.e.TestResourcesResolverLoader - Loaded 1 test resources resolvers: io.micronaut.testresources.testcontainers.GenericTestContainerProvider
10:50:31.579 [main] INFO i.m.testresources.server.Application - A Micronaut Test Resources server is listening on port 43207, started in 182ms
10:50:33.164 [default-nioEventLoopGroup-1-2] INFO i.m.t.e.TestResourcesResolverLoader - Loaded 1 test resources resolvers: io.micronaut.testresources.testcontainers.GenericTestContainerProvider
> Task :test
AuthorControllerSpec STANDARD_OUT
10:50:32.581 [Test worker] INFO i.m.context.env.DefaultEnvironment - Established active environments: [test]
10:50:33.131 [multithreadEventLoopGroup-1-1] DEBUG i.m.h.client.netty.DefaultHttpClient - Sending HTTP GET to http://localhost:43207/requirements/entries
10:50:33.190 [multithreadEventLoopGroup-1-1] DEBUG i.m.h.client.netty.DefaultHttpClient - Received response 200 from http://localhost:43207/requirements/entries
10:50:33.216 [multithreadEventLoopGroup-1-2] DEBUG i.m.h.client.netty.DefaultHttpClient - Sending HTTP POST to http://localhost:43207/list
10:50:33.246 [multithreadEventLoopGroup-1-2] DEBUG i.m.h.client.netty.DefaultHttpClient - Received response 200 from http://localhost:43207/list
10:50:33.249 [multithreadEventLoopGroup-1-3] DEBUG i.m.h.client.netty.DefaultHttpClient - Sending HTTP GET to http://localhost:43207/requirements/entries
10:50:33.254 [multithreadEventLoopGroup-1-3] DEBUG i.m.h.client.netty.DefaultHttpClient - Received response 200 from http://localhost:43207/requirements/entries
10:50:33.258 [multithreadEventLoopGroup-1-4] DEBUG i.m.h.client.netty.DefaultHttpClient - Sending HTTP POST to http://localhost:43207/list
10:50:33.262 [multithreadEventLoopGroup-1-4] DEBUG i.m.h.client.netty.DefaultHttpClient - Received response 200 from http://localhost:43207/list
10:50:33.367 [Test worker] INFO i.m.c.h.g.HibernateDatastoreFactory - Starting GORM for Hibernate
10:50:33.883 [Test worker] INFO org.hibernate.Version - HHH000412: Hibernate ORM core version 5.6.11.Final
10:50:33.984 [Test worker] INFO o.h.validator.internal.util.Version - HV000001: Hibernate Validator 6.2.5.Final
10:50:34.074 [Test worker] INFO o.h.annotations.common.Version - HCANN000001: Hibernate Commons Annotations {5.1.2.Final}
10:50:34.139 [Test worker] INFO org.hibernate.dialect.Dialect - HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
AuthorControllerSpec > It fails to get an non-existing Author > example.controller.AuthorControllerSpec.It fails to get an non-existing Author [badId: 546252431, #0] STANDARD_OUT
10:50:34.879 [default-nioEventLoopGroup-3-2] DEBUG i.m.h.client.netty.DefaultHttpClient - Sending HTTP GET to http://localhost:37361/author/546252431
AuthorControllerSpec > It fails to get an non-existing Author > example.controller.AuthorControllerSpec.It fails to get an non-existing Author [badId: 546252431, #0] STANDARD_ERROR
error.ErrorContextWithoutStacktrace: Author with id 546252431 not found.
AuthorControllerSpec > It fails to get an non-existing Author > example.controller.AuthorControllerSpec.It fails to get an non-existing Author [badId: 546252431, #0] STANDARD_OUT
10:50:34.999 [default-nioEventLoopGroup-3-3] ERROR i.m.http.server.RouteExecutor - Unexpected error occurred: Required argument [HttpRequest request] not specified
io.micronaut.web.router.exceptions.UnsatisfiedRouteException: Required argument [HttpRequest request] not specified
at io.micronaut.web.router.exceptions.UnsatisfiedRouteException.create(UnsatisfiedRouteException.java:76)
at io.micronaut.web.router.AbstractRouteMatch.execute(AbstractRouteMatch.java:297)
at io.micronaut.web.router.RouteMatch.execute(RouteMatch.java:111)
at io.micronaut.http.context.ServerRequestContext.with(ServerRequestContext.java:103)
at io.micronaut.http.server.RouteExecutor.lambda$executeRoute$14(RouteExecutor.java:659)
at reactor.core.publisher.FluxDeferContextual.subscribe(FluxDeferContextual.java:49)
[Skipped a lot of reactive frames]
at reactor.core.publisher.Flux.subscribe(Flux.java:8522)
at io.micronaut.http.server.netty.RoutingInBoundHandler.handleRouteMatch(RoutingInBoundHandler.java:601)
at io.micronaut.http.server.netty.RoutingInBoundHandler.channelRead0(RoutingInBoundHandler.java:457)
at io.micronaut.http.server.netty.RoutingInBoundHandler.channelRead0(RoutingInBoundHandler.java:147)
at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:99)
[Skipped a lot of netty channel stuff]
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:833)
10:50:35.031 [default-nioEventLoopGroup-3-2] DEBUG i.m.h.client.netty.DefaultHttpClient - Received response 500 from http://localhost:37361/author/546252431
10:50:35.049 [Test worker] ERROR i.m.r.intercept.RecoveryInterceptor - Type [example.controller.Api$Intercepted] executed with error: error.ErrorResource#475fb7
io.micronaut.http.client.exceptions.HttpClientResponseException: error.ErrorResource#475fb7
at io.micronaut.http.client.netty.DefaultHttpClient$FullHttpResponseHandler.makeErrorFromRequestBody(DefaultHttpClient.java:2226)
at io.micronaut.http.client.netty.DefaultHttpClient$FullHttpResponseHandler.buildResponse(DefaultHttpClient.java:2199)
at io.micronaut.http.client.netty.DefaultHttpClient$FullHttpResponseHandler.buildResponse(DefaultHttpClient.java:2122)
at io.micronaut.http.client.netty.DefaultHttpClient$BaseHttpResponseHandler.channelReadInstrumented(DefaultHttpClient.java:2097)
at io.micronaut.http.client.netty.DefaultHttpClient$FullHttpResponseHandler.channelReadInstrumented(DefaultHttpClient.java:2158)
at io.micronaut.http.client.netty.DefaultHttpClient$FullHttpResponseHandler.channelReadInstrumented(DefaultHttpClient.java:2122)
at io.micronaut.http.client.netty.SimpleChannelInboundHandlerInstrumented.channelRead0(SimpleChannelInboundHandlerInstrumented.java:49)
at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:99)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)
[Skipped a lot of netty channel stuff]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:788)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:833)
Suppressed: java.lang.Exception: #block terminated with an error
at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:99)
at reactor.core.publisher.Flux.blockFirst(Flux.java:2600)
at io.micronaut.http.client.netty.DefaultHttpClient$1.exchange(DefaultHttpClient.java:498)
at io.micronaut.http.client.netty.DefaultHttpClient$1.retrieve(DefaultHttpClient.java:505)
at io.micronaut.http.client.interceptor.HttpClientIntroductionAdvice.lambda$intercept$5(HttpClientIntroductionAdvice.java:409)
at io.micronaut.http.client.interceptor.HttpClientIntroductionAdvice.handleBlockingCall(HttpClientIntroductionAdvice.java:508)
at io.micronaut.http.client.interceptor.HttpClientIntroductionAdvice.intercept(HttpClientIntroductionAdvice.java:408)
at io.micronaut.aop.chain.MethodInterceptorChain.proceed(MethodInterceptorChain.java:137)
at io.micronaut.retry.intercept.RecoveryInterceptor.intercept(RecoveryInterceptor.java:92)
at io.micronaut.aop.chain.MethodInterceptorChain.proceed(MethodInterceptorChain.java:137)
at example.controller.Api$Intercepted.getAuthor(Unknown Source)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.codehaus.groovy.runtime.callsite.PlainObjectMetaMethodSite.doInvoke(PlainObjectMetaMethodSite.java:43)
at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoCachedMethodSiteNoUnwrap.invoke(PojoMetaMethodSite.java:203)
at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:56)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:148)
at example.controller.AuthorControllerSpec.$spock_feature_0_0(AuthorControllerSpec.groovy:33)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.spockframework.util.ReflectionUtil.invokeMethod(ReflectionUtil.java:198)
[Skipped a lot of gradle, junit, and spock stuff]
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
AuthorControllerSpec > It fails to get an non-existing Author > example.controller.AuthorControllerSpec.It fails to get an non-existing Author [badId: 546252431, #0] FAILED
org.spockframework.runtime.SpockComparisonFailure at AuthorControllerSpec.groovy:37
You imported the wrong HttpRequest
Instead of import java.net.http.HttpRequest you should import import io.micronaut.http.HttpRequest.
But even then you will not catch HttpClientResponseException because you don't use any Client in your test. If you want to receive this exception you should write something like this:
#Inject
#Client("/author")
HttpClient client
#IgnoreRest
def "It fails to get an non-existing Author with an HttpClient"() {
given:
def token = viewer()
when:
def author = client.toBlocking().exchange(HttpRequest.create(
HttpMethod.GET,
"/" + badId
).bearerAuth(token))
then:
def ex = thrown(HttpClientResponseException)
ex.status == NOT_FOUND
ex.getResponse().getBody(ErrorResource).map {
assert it.message == "Author with id ${badId} not found."
it
}.isPresent()
where:
badId = anyInt()
}
Related
I'm having same problems as this question
with rabbitmq dropping connection same second as it has started. I have a minimal project on github.
It is a Spring Boot project where two docker containers are running. One with RMQ and one with psql. Using the containers when running the project is no problem, just the rabbitmq testcontainer that seem to be unstable. I did try to have the container wrapped in a generic container instead, with same result.
The first test to see if the containers are up and running passes, so it seems to be something with the amqp connection only.
Configclass:
#SpringBootTest(classes = TestContainersDemoApplication.class)
#Testcontainers
#AutoConfigureMockMvc
#ExtendWith(SpringExtension.class)
public abstract class TestContainersConfig {
#Autowired
public MockMvc mockMvc;
#Container
public static final RabbitMQContainer rabbitMQContainer = new RabbitMQContainer("rabbitmq:3.8-management-alpine");
#Container
public static PostgreSQLContainer sqlContainer = new PostgreSQLContainer("postgres:latest")
.withDatabaseName("demo")
.withUsername("postgres")
.withPassword("postgres");
#DynamicPropertySource
static void registerProperties(DynamicPropertyRegistry dynamicPropertyRegistry) {
dynamicPropertyRegistry.add("spring.datasource.url", () -> sqlContainer.getJdbcUrl());
dynamicPropertyRegistry.add("spring.datasource.username", () -> sqlContainer.getUsername());
dynamicPropertyRegistry.add("spring.datasource.password", () -> sqlContainer.getPassword());
dynamicPropertyRegistry.add("spring.rabbitmq.host", rabbitMQContainer::getHost);
dynamicPropertyRegistry.add("spring.rabbitmq.port", rabbitMQContainer::getAmqpPort);
}
static {
Startables.deepStart(Stream.of(rabbitMQContainer, sqlContainer)).join();
}
}
The stacktrace seem to be identical as the linked question:
2022-11-18 21:00:23.555 INFO 441007 --- [ main] o.s.a.r.l.SimpleMessageListenerContainer : Broker not available; cannot force queue declarations during start: java.io.IOException
2022-11-18 21:00:23.559 INFO 441007 --- [ntContainer#0-1] o.s.a.r.c.CachingConnectionFactory : Attempting to connect to: [localhost:49596]
2022-11-18 21:00:23.770 WARN 441007 --- [127.0.0.1:49596] c.r.c.impl.ForgivingExceptionHandler : An unexpected connection driver error occurred (Exception message: Socket closed)
2022-11-18 21:00:23.773 ERROR 441007 --- [ntContainer#0-1] o.s.a.r.l.SimpleMessageListenerContainer : Failed to check/redeclare auto-delete queue(s).
org.springframework.amqp.AmqpIOException: java.io.IOException
at org.springframework.amqp.rabbit.support.RabbitExceptionTranslator.convertRabbitAccessException(RabbitExceptionTranslator.java:70) ~[spring-rabbit-2.4.7.jar:2.4.7]
at org.springframework.amqp.rabbit.connection.AbstractConnectionFactory.createBareConnection(AbstractConnectionFactory.java:602) ~[spring-rabbit-2.4.7.jar:2.4.7]
at org.springframework.amqp.rabbit.connection.CachingConnectionFactory.createConnection(CachingConnectionFactory.java:725) ~[spring-rabbit-2.4.7.jar:2.4.7]
at org.springframework.amqp.rabbit.connection.ConnectionFactoryUtils.createConnection(ConnectionFactoryUtils.java:252) ~[spring-rabbit-2.4.7.jar:2.4.7]
at org.springframework.amqp.rabbit.core.RabbitTemplate.doExecute(RabbitTemplate.java:2180) ~[spring-rabbit-2.4.7.jar:2.4.7]
at org.springframework.amqp.rabbit.core.RabbitTemplate.execute(RabbitTemplate.java:2153) ~[spring-rabbit-2.4.7.jar:2.4.7]
at org.springframework.amqp.rabbit.core.RabbitTemplate.execute(RabbitTemplate.java:2133) ~[spring-rabbit-2.4.7.jar:2.4.7]
at org.springframework.amqp.rabbit.core.RabbitAdmin.getQueueInfo(RabbitAdmin.java:463) ~[spring-rabbit-2.4.7.jar:2.4.7]
at org.springframework.amqp.rabbit.core.RabbitAdmin.getQueueProperties(RabbitAdmin.java:447) ~[spring-rabbit-2.4.7.jar:2.4.7]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.attemptDeclarations(AbstractMessageListenerContainer.java:1930) ~[spring-rabbit-2.4.7.jar:2.4.7]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.redeclareElementsIfNecessary(AbstractMessageListenerContainer.java:1911) ~[spring-rabbit-2.4.7.jar:2.4.7]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.initialize(SimpleMessageListenerContainer.java:1377) ~[spring-rabbit-2.4.7.jar:2.4.7]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1223) ~[spring-rabbit-2.4.7.jar:2.4.7]
at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]
Caused by: java.io.IOException: null
at com.rabbitmq.client.impl.AMQChannel.wrap(AMQChannel.java:129) ~[amqp-client-5.14.2.jar:5.14.2]
at com.rabbitmq.client.impl.AMQChannel.wrap(AMQChannel.java:125) ~[amqp-client-5.14.2.jar:5.14.2]
at com.rabbitmq.client.impl.AMQConnection.start(AMQConnection.java:396) ~[amqp-client-5.14.2.jar:5.14.2]
at com.rabbitmq.client.ConnectionFactory.newConnection(ConnectionFactory.java:1225) ~[amqp-client-5.14.2.jar:5.14.2]
at com.rabbitmq.client.ConnectionFactory.newConnection(ConnectionFactory.java:1173) ~[amqp-client-5.14.2.jar:5.14.2]
at org.springframework.amqp.rabbit.connection.AbstractConnectionFactory.connectAddresses(AbstractConnectionFactory.java:640) ~[spring-rabbit-2.4.7.jar:2.4.7]
at org.springframework.amqp.rabbit.connection.AbstractConnectionFactory.connect(AbstractConnectionFactory.java:615) ~[spring-rabbit-2.4.7.jar:2.4.7]
at org.springframework.amqp.rabbit.connection.AbstractConnectionFactory.createBareConnection(AbstractConnectionFactory.java:565) ~[spring-rabbit-2.4.7.jar:2.4.7]
... 12 common frames omitted
Caused by: com.rabbitmq.client.ShutdownSignalException: connection error
at com.rabbitmq.utility.ValueOrException.getValue(ValueOrException.java:66) ~[amqp-client-5.14.2.jar:5.14.2]
at com.rabbitmq.utility.BlockingValueOrException.uninterruptibleGetValue(BlockingValueOrException.java:36) ~[amqp-client-5.14.2.jar:5.14.2]
at com.rabbitmq.client.impl.AMQChannel$BlockingRpcContinuation.getReply(AMQChannel.java:502) ~[amqp-client-5.14.2.jar:5.14.2]
at com.rabbitmq.client.impl.AMQConnection.start(AMQConnection.java:326) ~[amqp-client-5.14.2.jar:5.14.2]
... 17 common frames omitted
Caused by: java.io.EOFException: null
at java.base/java.io.DataInputStream.readUnsignedByte(DataInputStream.java:296) ~[na:na]
at com.rabbitmq.client.impl.Frame.readFrom(Frame.java:91) ~[amqp-client-5.14.2.jar:5.14.2]
at com.rabbitmq.client.impl.SocketFrameHandler.readFrame(SocketFrameHandler.java:184) ~[amqp-client-5.14.2.jar:5.14.2]
at com.rabbitmq.client.impl.AMQConnection$MainLoop.run(AMQConnection.java:665) ~[amqp-client-5.14.2.jar:5.14.2]
... 1 common frames omitted
2022-11-18 21:00:23.774 INFO 441007 --- [ntContainer#0-1] o.s.a.r.c.CachingConnectionFactory : Attempting to connect to: [localhost:49596]
2022-11-18 21:00:23.978 WARN 441007 --- [127.0.0.1:49596] c.r.c.impl.ForgivingExceptionHandler : An unexpected connection driver error occurred (Exception message: Socket closed)
2022-11-18 21:00:24.022 INFO 441007 --- [ main] message.MessageControllerTest : Started MessageControllerTest in 4.155 seconds (JVM running for 14.327)
2022-11-18 21:00:24.378 INFO 441007 --- [ main] message.MessageControllerTest : sqlcontianers are working
2022-11-18 21:00:24.390 INFO 441007 --- [ main] message.MessageControllerTest : InsertNewMessage
2022-11-18 21:00:24.447 INFO 441007 --- [ main] o.s.a.r.c.CachingConnectionFactory : Attempting to connect to: [localhost:49596]```
You are manually managing the container lifecycle, which is a good approach:
Startables.deepStart(Stream.of(rabbitMQContainer, sqlContainer)).join();
In this case, remove the #Container and #Testcontainers annotation that interfere with the test lifecycle.
Your tests fails with:
Caused by: com.rabbitmq.client.AuthenticationFailureException: ACCESS_REFUSED - Login was refused using authentication mechanism PLAIN. For details see the broker logfile.
The default admin username and password in RabbitMQContainer should be guest. Changing it accordingly in the application.yml makes the test pass. Once changed it will also work when still using the #Testcontainers extension (although not recommended in this case).
Btw. thanks for sharing the reproducer, it made debugging very easy.
I am presently developing a Java 11 Spring boot application.
Within a CompletableFuture I am firing a load of REST requests to a webservice. Only one of them (randomly it seems) results in a TimeoutException though it is followed by a successful status 200 OK received response in the logging. Following the (anonymized) log entries:
[Thread-6] INFO n.d.b.a.b.i.RESTInterceptor - Request : <url value>?code=abcd&begindatum=2018-10-01&einddatum=2018-10-02
[http-nio-8080-exec-1] ERROR o.a.c.c.C.[.[.[.[dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [/xxx] threw exception [Request processing failed; nested exception is java.util.concurrent.CompletionException: java.util.concurrent.TimeoutException] with root cause
java.util.concurrent.TimeoutException: null
at java.base/java.util.concurrent.CompletableFuture$Timeout.run(CompletableFuture.java:2792)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
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:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
[Thread-6] DEBUG n.d.b.a.b.i.RESTInterceptor - Response statuscode : 200 OK
[Thread-6] DEBUG n.d.b.a.b.i.RESTInterceptor - Response headers : [X-Application-Context:"yyyy", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", Server:"CD", X-Powered-By:"Unknown", Content-Type:"application/json;charset=UTF-8", Date:"Tue, 06 Apr 2021 15:23:16 GMT", Connection:"close", X-Frame-Options:"SAMEORIGIN", X-XSS-Protection:"1;mode=block", X-Content-Type-Options:"nosniff"]
[Thread-6] INFO n.d.b.a.b.i.RESTInterceptor - Response : [{"begindatum":"1993-01-01","id":"aaaaa","vanInstellingserkenningId":"bbbbb","naarInstellingserkenningId":"ccccc","soort":"HIERARCHISCH","naarInstellingserkenning":{"id":"ddddd","type":"ERKENDE_ONDERWIJSINSTELLING","code":"abcd"},"vanInstellingserkenning":{"id":"kkkk","type":"BEVOEGD_GEZAG","code":"12345"}}]
Is there someone having the same experience? I cannot see any difference in the successfully completed requests and the 'failing' one.
After deeper analysis of the problem I finally found out that the TimeoutException is thrown from another Future's handling, elsewhere in the application. The confusion I had that the handling of futures (asynchronous tasks, each in their own Thread) is not what it looks like in a log-file. The shown TimeoutException in the log-snippet is not thrown in the request-response interaction that is shown.
Sorry for the confusion, but maybe others may be helped by this answer.
I have in my AWS VPC a cluster of ES with 2 nodes. On top of those nodes I have a load balancer. In the same vpc I have a microservice that accesses Elasticsearch via RestHighLevelClient version 7.5.2 .
I create the client in the following manner :
public class ESClientWrapper {
#Getter
private RestHighLevelClient client;
public ESClientWrapper() throws IOException {
FileInputStream propertiesFile = new FileInputStream("/var/elastic.properties");
Properties properties = new Properties();
properties.load(propertiesFile );
RestClientBuilder builder = RestClient.builder(new HttpHost(
properties .getProperty("host"),
Integer.parseInt(properties.getProperty("port"))
));
this.client = new RestHighLevelClient(builder);
}
}
When my micro service doesn't get requests for a long time (12h..) there are occurrences when the first response that is sent (or a few after..) are getting the following error:
2020-09-09 07:03:13.106 INFO 1 --- [nio-8080-exec-1] c.a.a.services.CustomersMetadataService : Trying to add the following role : {role=a2}
2020-09-09 07:03:13.106 INFO 1 --- [nio-8080-exec-1] c.a.a.e.repositories.ESRepository : Trying to insert the following document to app-index : {role=a2}
2020-09-09 07:03:13.109 ERROR 1 --- [nio-8080-exec-1] c.a.a.e.dal.ESRepository : Failed to add customer : {role=a2}
java.io.IOException: Connection reset by peer
at org.elasticsearch.client.RestClient.extractAndWrapCause(RestClient.java:828) ~[elasticsearch-rest-client-7.5.2.jar!/:7.5.2]
at org.elasticsearch.client.RestClient.performRequest(RestClient.java:248) ~[elasticsearch-rest-client-7.5.2.jar!/:7.5.2]
at org.elasticsearch.client.RestClient.performRequest(RestClient.java:235) ~[elasticsearch-rest-client-7.5.2.jar!/:7.5.2]
at org.elasticsearch.client.RestHighLevelClient.internalPerformRequest(RestHighLevelClient.java:1514) ~[elasticsearch-rest-high-level-client-7.5.2.jar!/:7.5.2]
at org.elasticsearch.client.RestHighLevelClient.performRequest(RestHighLevelClient.java:1484) ~[elasticsearch-rest-high-level-client-7.5.2.jar!/:7.5.2]
at org.elasticsearch.client.RestHighLevelClient.performRequestAndParseEntity(RestHighLevelClient.java:1454) ~[elasticsearch-rest-high-level-client-7.5.2.jar!/:7.5.2]
at org.elasticsearch.client.RestHighLevelClient.index(RestHighLevelClient.java:871) ~[elasticsearch-rest-high-level-client-7.5.2.jar!/:7.5.2]
....
....
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.35.jar!/:9.0.35]
at java.base/java.lang.Thread.run(Thread.java:836) ~[na:na]
Caused by: java.io.IOException: Connection reset by peer
at java.base/sun.nio.ch.FileDispatcherImpl.read0(Native Method) ~[na:na]
at java.base/sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:39) ~[na:na]
at java.base/sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:276) ~[na:na]
at java.base/sun.nio.ch.IOUtil.read(IOUtil.java:245) ~[na:na]
at java.base/sun.nio.ch.IOUtil.read(IOUtil.java:223) ~[na:na]
at java.base/sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:358) ~[na:na]
at org.apache.http.impl.nio.reactor.SessionInputBufferImpl.fill(SessionInputBufferImpl.java:231) ~[httpcore-nio-4.4.13.jar!/:4.4.13]
at org.apache.http.impl.nio.codecs.AbstractMessageParser.fillBuffer(AbstractMessageParser.java:136) ~[httpcore-nio-4.4.13.jar!/:4.4.13]
at org.apache.http.impl.nio.DefaultNHttpClientConnection.consumeInput(DefaultNHttpClientConnection.java:241) ~[httpcore-nio-4.4.13.jar!/:4.4.13]
at org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:81) ~[httpasyncclient-4.1.4.jar!/:4.1.4]
at org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:39) ~[httpasyncclient-4.1.4.jar!/:4.1.4]
at org.apache.http.impl.nio.reactor.AbstractIODispatch.inputReady(AbstractIODispatch.java:114) ~[httpcore-nio-4.4.13.jar!/:4.4.13]
at org.apache.http.impl.nio.reactor.BaseIOReactor.readable(BaseIOReactor.java:162) ~[httpcore-nio-4.4.13.jar!/:4.4.13]
at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:337) ~[httpcore-nio-4.4.13.jar!/:4.4.13]
at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:315) ~[httpcore-nio-4.4.13.jar!/:4.4.13]
at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:276) ~[httpcore-nio-4.4.13.jar!/:4.4.13]
at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:104) ~[httpcore-nio-4.4.13.jar!/:4.4.13]
at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:591) ~[httpcore-nio-4.4.13.jar!/:4.4.13]
... 1 common frames omitted
2020-09-09 07:06:55.109 INFO 1 --- [nio-8080-exec-2] c.a.a.services.MyService : Trying to add the following role : {role=a2}
2020-09-09 07:06:55.109 INFO 1 --- [nio-8080-exec-2] c.a.a.e.repositories.ESRepository : Trying to insert the following document to index app-index: {role=a2}
2020-09-09 07:06:55.211 INFO 1 --- [nio-8080-exec-2] c.a.a.e.dal.ESRepository : IndexResponse[index=app-index,type=_doc,id=x532323272533321870287,version=1,result=created,seqNo=70,primaryTerm=1,shards={"total":2,"successful":2,"failed":0}]
As you can see, 3 minutes after the failed request the next request was successfully handeled by ES. What can kill the request ? I checked Elasticsearch logs and didn't see any indication for killing connection. The MS is in the same vpc as elastic so it isn't passing through any firewall that might kill it.
I found the following issue in github that suggested to increase the default connection timeout but I'm wondering if the issue here is really a timeout problem and if increasing the default time is really the best solution..
Also, I found this bug opened in their repo regarding the same problem but without any answers.
UPDATE
I noticed that even after 10 minutes my service is up this happens. My service started and sent a query to ES and everything worked well. After 10 minutes I sent insert request and it failed on connection reset by peer.
In the end I didn't find a problem in my configuration/implementation. It seems like a bug in the implementation of Elasticsearch's RestHighLevelClient.
I implemented a retry mechanism that wraps the RestHighLevelClient and retries the query if I get the same error. I used Spring #Retry annotation for this solution.
I was facing the same issue. Everything worked fine, but after some time a single request got refused.
The solution (in my case) was to set the keepalive property of the tcp connection with:
final RestClientBuilder restClientBuilder = RestClient.builder(...);
restClientBuilder.setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder.setDefaultIOReactorConfig(IOReactorConfig.custom()
.setSoKeepAlive(true)
.build()))
Found here:
https://github.com/elastic/elasticsearch/issues/65213
I'm trying to send and receive a TCP message via Citrus-Framework, where I used this thread as a reference:
Receiving messages from tcp server with Citrus framework and Spring Integration times out
I'm using a python message repeater, which returns the received message. I receive a payload with python and returns it but citrus times out. I tried all serializers (except SingleTerminatior, causes a context error).
I tried different serializers but none seem to solve my problem, Citrus always times out.
15:03:58,013 DEBUG t.TestContextFactory| Created new test context - using global variables: '{}'
15:03:58,024 INFO port.LoggingReporter|
15:03:58,024 INFO port.LoggingReporter|------------------------------------------------------------------------
15:03:58,024 DEBUG port.LoggingReporter| STARTING TEST sendSpringIntegrationMessageTest <com.consol.citrus.samples>
15:03:58,025 INFO port.LoggingReporter|
15:03:58,025 DEBUG citrus.TestCase| Initializing test case
15:03:58,026 DEBUG context.TestContext| Setting variable: citrus.test.name with value: 'sendSpringIntegrationMessageTest'
15:03:58,027 DEBUG context.TestContext| Setting variable: citrus.test.package with value: 'com.consol.citrus.samples'
15:03:58,028 DEBUG citrus.TestCase| Test variables:
15:03:58,028 DEBUG citrus.TestCase| citrus.test.name = sendSpringIntegrationMessageTest
15:03:58,028 DEBUG citrus.TestCase| citrus.test.package = com.consol.citrus.samples
15:03:58,029 INFO port.LoggingReporter|
15:03:58,030 DEBUG port.LoggingReporter| TEST STEP 1/2: send
15:03:58,049 DEBUG nnel.ChannelProducer| Sending message to channel: 'input'
15:03:58,055 DEBUG nnel.ChannelProducer| Message to send is:
DEFAULTMESSAGE [id: c5c61991-f567-42bd-9302-1f8e1fa16225, payload: Req][headers: {citrus_message_type=XML, citrus_message_id=c5c61991-f567-42bd-9302-1f8e1fa16225, citrus_message_timestamp=1539090238031}]
15:03:58,164 INFO nnel.ChannelProducer| Message was sent to channel: 'input'
15:03:58,165 INFO port.LoggingReporter|
15:03:58,166 DEBUG port.LoggingReporter| TEST STEP 1/2 SUCCESS
15:03:58,166 INFO port.LoggingReporter|
15:03:58,166 DEBUG port.LoggingReporter| TEST STEP 2/2: receive
15:03:58,168 DEBUG nnel.ChannelConsumer| Receiving message from: replies
15:04:03,171 INFO port.LoggingReporter|
15:04:03,172 ERROR port.LoggingReporter| TEST FAILED sendSpringIntegrationMessageTest <com.consol.citrus.samples> Nested exception is:
at com.consol.citrus.exceptions.ActionTimeoutException: Action timeout while receiving message from channel 'replies'
at com.consol.citrus.channel.ChannelConsumer.receive(ChannelConsumer.java:97)
at com.consol.citrus.messaging.AbstractSelectiveMessageConsumer.receive(AbstractSelectiveMessageConsumer.java:50)
at com.consol.citrus.actions.ReceiveMessageAction.receive(ReceiveMessageAction.java:141)
at com.consol.citrus.actions.ReceiveMessageAction.doExecute(ReceiveMessageAction.java:120)
at com.consol.citrus.actions.AbstractTestAction.execute(AbstractTestAction.java:46)
at com.consol.citrus.dsl.actions.DelegatingTestAction.doExecute(DelegatingTestAction.java:54)
at com.consol.citrus.actions.AbstractTestAction.execute(AbstractTestAction.java:46)
at com.consol.citrus.TestCase.executeAction(TestCase.java:234)
at com.consol.citrus.TestCase.doExecute(TestCase.java:153)
at com.consol.citrus.actions.AbstractTestAction.execute(AbstractTestAction.java:46)
at com.consol.citrus.Citrus.run(Citrus.java:403)
at com.consol.citrus.dsl.testng.TestNGCitrusTest.invokeTestMethod(TestNGCitrusTest.java:125)
at com.consol.citrus.dsl.testng.TestNGCitrusTestDesigner.invokeTestMethod(TestNGCitrusTestDesigner.java:73)
at com.consol.citrus.dsl.testng.TestNGCitrusTest.run(TestNGCitrusTest.java:110)
...
My context seems to be right (I'm using spring-integration-ip 5.0.8-RELEASE), there is no exception when executing the test (except using SingleTerminatior):
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
... >
<citrus:channel-endpoint id="citrusServiceInputEndpoint"
channel-name="input" />
<citrus:channel-endpoint id="citrusServiceRepliesEndpoint"
channel-name="replies" />
<int-ip:tcp-connection-factory id="client"
type="client" host="127.0.0.1"
port="33500" single-use="false"
so-timeout="10000" using-nio="true"
deserializer="javaSerializer"
serializer="javaSerializer" />
<bean id="javaSerializer"
class="org.springframework.integration.ip.tcp.serializer.ByteArrayLfSerializer" />
<int:channel id="input" />
<int:channel id="replies">
<int:queue />
</int:channel>
<int-ip:tcp-outbound-channel-adapter
id="outboundClient" channel="input" connection-factory="client" />
<int-ip:tcp-inbound-channel-adapter
id="inboundClient" channel="replies" connection-factory="client" />
</beans>
I appreciate any kind of help
Thanks
because I'm new to spring here is the dependency I added from my part:
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-ip</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
This is the debug output of citrus:
22:47:41,071 DEBUG port.LoggingReporter| TEST STEP 1/2: send
22:47:41,085 DEBUG tListableBeanFactory| Returning cached instance of singleton bean 'citrusServiceInputEndpoint'
22:47:41,086 DEBUG nnel.ChannelProducer| Sending message to channel: 'input'
22:47:41,086 DEBUG nnel.ChannelProducer| Message to send is:
DEFAULTMESSAGE [id: 7d4f4c7a-92d0-462c-b695-c32fc7e697ae, payload: Req][headers: {citrus_message_type=XML, citrus_message_id=7d4f4c7a-92d0-462c-b695-c32fc7e697ae, citrus_message_timestamp=1539118061073}]
22:47:41,087 DEBUG tListableBeanFactory| Returning cached instance of singleton bean 'input'
22:47:41,091 DEBUG hannel.DirectChannel| preSend on channel 'input', message:
GenericMessage [payload=Req, headers={citrus_message_timestamp=1539118061073, citrus_message_type=XML, id=33295f63-948f-6bcf-289f-d5e1df8dc98b, citrus_message_id=7d4f4c7a-92d0-462c-b695-c32fc7e697ae, timestamp=1539118061091}]
22:47:41,092 DEBUG endingMessageHandler| org.springframework.integration.ip.tcp.TcpSendingMessageHandler#0 received message:
GenericMessage [payload=Req, headers={citrus_message_timestamp=1539118061073, citrus_message_type=XML, id=33295f63-948f-6bcf-289f-d5e1df8dc98b, citrus_message_id=7d4f4c7a-92d0-462c-b695-c32fc7e697ae, timestamp=1539118061091}]
22:47:41,092 DEBUG entConnectionFactory| Opening new socket connection to 127.0.0.1:33500
22:47:41,106 DEBUG ion.TcpNioConnection| New connection localhost:33500:55108:33be3b24-f5ae-4594-83e9-c7eb0f104b1f
22:47:41,110 DEBUG entConnectionFactory| client: Added new connection: localhost:33500:55108:33be3b24-f5ae-4594-83e9-c7eb0f104b1f
22:47:41,113 DEBUG endingMessageHandler| Got Connection localhost:33500:55108:33be3b24-f5ae-4594-83e9-c7eb0f104b1f
22:47:41,114 DEBUG ion.TcpNioConnection| localhost:33500:55108:33be3b24-f5ae-4594-83e9-c7eb0f104b1f writing 4
22:47:41,116 DEBUG ion.TcpNioConnection| localhost:33500:55108:33be3b24-f5ae-4594-83e9-c7eb0f104b1f Message sent GenericMessage [payload=Req, headers={citrus_message_timestamp=1539118061073, citrus_message_type=XML, id=33295f63-948f-6bcf-289f-d5e1df8dc98b, citrus_message_id=7d4f4c7a-92d0-462c-b695-c32fc7e697ae, timestamp=1539118061091}]
22:47:41,117 DEBUG channel.DirectChannel| postSend (sent=true) on channel 'input', message: GenericMessage [payload=Req, headers={citrus_message_timestamp=1539118061073, citrus_message_type=XML, id=33295f63-948f-6bcf-289f-d5e1df8dc98b, citrus_message_id=7d4f4c7a-92d0-462c-b695-c32fc7e697ae, timestamp=1539118061091}]
22:47:41,118 INFO nnel.ChannelProducer| Message was sent to channel: 'input'
22:47:41,118 INFO port.LoggingReporter|
22:47:41,119 DEBUG port.LoggingReporter| TEST STEP 1/2 SUCCESS
22:47:41,119 DEBUG tListableBeanFactory| Returning cached instance of singleton bean 'citrusServiceRepliesEndpoint'
22:47:41,120 INFO port.LoggingReporter|
22:47:41,121 DEBUG port.LoggingReporter| TEST STEP 2/2: receive
22:47:41,122 DEBUG tListableBeanFactory| Returning cached instance of singleton bean 'citrusServiceRepliesEndpoint'
22:47:41,124 DEBUG tListableBeanFactory| Returning cached instance of singleton bean 'response'
22:47:41,125 DEBUG nnel.ChannelConsumer| Receiving message from: response
22:47:46,130 INFO port.LoggingReporter|
22:47:46,131 ERROR port.LoggingReporter| TEST FAILED
sendSpringIntegrationMessageTest <com.consol.citrus.samples> Nested exception is:
com.consol.citrus.exceptions.ActionTimeoutException: Action timeout while receiving message from channel 'response'
...
I checked Wireshark and the payload ("Req") inclusive the linefeed was returned, which can be seen in the screenshot. Maybe I should mention I'm running this in an Ubuntu VM.
Wireshark screenshot
#CitrusTest(name = "sendSpringIntegrationMessageTest")
public void sendSpringIntegrationMessageTest() throws Exception {
send("citrusServiceInputEndpoint").payload("Req");
receive("citrusServiceRepliesEndpoint").payload("Req");
}
EDIT
ok there seem to be an issue in my python server. I changed the code a bit to see the received bytes on the console (before I was just counting the bytes) and suddenly the output of citrus changed.
11:40:54,924 DEBUG port.LoggingReporter| TEST STEP 2/2: receive
11:40:54,925 DEBUG tListableBeanFactory| Returning cached instance of singleton bean 'citrusServiceRepliesEndpoint'
11:40:54,925 DEBUG tListableBeanFactory| Returning cached instance of singleton bean 'response'
11:40:54,925 DEBUG nnel.ChannelConsumer| Receiving message from: response
11:40:54,928 DEBUG ion.TcpNioConnection| localhost:33500:55890:7537f5ed-f447-4b76-ba66-2ec59c7619a9 Reading...
11:40:54,929 DEBUG ion.TcpNioConnection| localhost:33500:55890:7537f5ed-f447-4b76-ba66-2ec59c7619a9 Running an assembler
11:40:54,929 DEBUG ion.TcpNioConnection| Read 4 into raw buffer
Exception in thread "pool-1-thread-3" java.lang.AbstractMethodError: org.springframework.integration.ip.tcp.connection.TcpMessageMapper.toMessage(Ljava/lang/Object;)Lorg/springframework/messaging/Message;
at org.springframework.integration.ip.tcp.connection.TcpNioConnection.convert(TcpNioConnection.java:358)
at org.springframework.integration.ip.tcp.connection.TcpNioConnection.run(TcpNioConnection.java:235)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
11:40:54,937 DEBUG ion.TcpNioConnection| localhost:33500:55890:7537f5ed-f447-4b76-ba66-2ec59c7619a9 Reading...
11:40:54,938 DEBUG ion.TcpNioConnection| Read 0 into raw buffer
11:40:59,930 INFO port.LoggingReporter|
11:40:59,931 ERROR port.LoggingReporter| TEST FAILED sendSpringIntegrationMessageTest <com.consol.citrus.samples> Nested exception is:
com.consol.citrus.exceptions.ActionTimeoutException: Action timeout while receiving message from channel 'response'
EDIT2
Because of the following post:
How to use Spring Integration 5 with Spring Boot 1.5.x
I switched from spring-integration-ip 5.0.8 to 4.3.9 and there the output changed one more time. Now my problem seems to move away from TCP issues to actual spring know-how.
15:04:12,318 DEBUG port.LoggingReporter| TEST STEP 2/2: receive
15:04:12,319 DEBUG tListableBeanFactory| Returning cached instance of singleton bean 'citrusServiceRepliesEndpoint'
15:04:12,319 DEBUG tListableBeanFactory| Returning cached instance of singleton bean 'replies'
15:04:12,319 DEBUG nnel.ChannelConsumer| Receiving message from: replies
15:04:12,327 DEBUG ion.TcpNioConnection| localhost:33500:56004:1174f4c6-608c-44c6-aeec-33da4074e195 Reading...
15:04:12,328 DEBUG ion.TcpNioConnection| localhost:33500:56004:1174f4c6-608c-44c6-aeec-33da4074e195 Running an assembler
15:04:12,329 DEBUG ion.TcpNioConnection| Read 4 into raw buffer
15:04:12,329 DEBUG ion.TcpNioConnection| localhost:33500:56004:1174f4c6-608c-44c6-aeec-33da4074e195 Reading...
15:04:12,330 DEBUG ion.TcpNioConnection| Read 0 into raw buffer
15:04:12,332 DEBUG yteArrayLfSerializer| Available to read:4
15:04:12,333 DEBUG tListableBeanFactory| Returning cached instance of singleton bean 'messageBuilderFactory'
15:04:12,336 DEBUG channel.QueueChannel| preSend on channel 'replies', message: GenericMessage [payload=byte[3], headers={ip_tcp_remotePort=33500, ip_connectionId=localhost:33500:56004:1174f4c6-608c-44c6-aeec-33da4074e195, ip_localInetAddress=0.0.0.0/0.0.0.0, ip_address=127.0.0.1, id=9bd90a54-cc2b-d3d0-ca63-6355f53dee7c, ip_hostname=localhost, timestamp=1539176652336}]
15:04:12,339 DEBUG channel.QueueChannel| postReceive on channel 'replies', message: GenericMessage [payload=byte[3], headers={ip_tcp_remotePort=33500, ip_connectionId=localhost:33500:56004:1174f4c6-608c-44c6-aeec-33da4074e195, ip_localInetAddress=0.0.0.0/0.0.0.0, ip_address=127.0.0.1, id=9bd90a54-cc2b-d3d0-ca63-6355f53dee7c, ip_hostname=localhost, timestamp=1539176652336}]
15:04:12,340 DEBUG nnel.ChannelConsumer| Received message from: replies
15:04:12,340 DEBUG tListableBeanFactory| Returning cached instance of singleton bean 'citrusServiceRepliesEndpoint'
15:04:12,354 DEBUG channel.QueueChannel| postSend (sent=true) on channel 'replies', message: GenericMessage [payload=byte[3], headers={ip_tcp_remotePort=33500, ip_connectionId=localhost:33500:56004:1174f4c6-608c-44c6-aeec-33da4074e195, ip_localInetAddress=0.0.0.0/0.0.0.0, ip_address=127.0.0.1, id=9bd90a54-cc2b-d3d0-ca63-6355f53dee7c, ip_hostname=localhost, timestamp=1539176652336}]
15:04:12,379 INFO port.LoggingReporter|
15:04:12,381 ERROR port.LoggingReporter| TEST FAILED sendSpringIntegrationMessageTest <com.consol.citrus.samples> Nested exception is:
com.consol.citrus.exceptions.CitrusRuntimeException: Could not find proper message validator for message type 'XML', please define a capable message validator for this message type
EDIT3
Seems like after adjusting my environment a lot for test, I was lastly missing this line in my context file:
<int:object-to-string-transformer id="transformer" input-channel="replies" output-channel="response" />
Thanks for nudging me into the right direction.
Faced spring integration java-dsl issue, I'm stuck. This is a code I have for my flow declaration:
#Bean
public IntegrationFlow orchestrationFlow() {
return IntegrationFlows.from(
Jms.messageDrivenChannelAdapter(queueConnectionFactory())
.destination(bookingQueue())
.outputChannel(bookingChannel()))
.<String, BookingRequest>transform(s -> {
Ticket t = new Gson().fromJson(s, Ticket.class);
return new BookingRequest()
.setMovieId(t.getMovie().getId())
.setRow(t.getSeat().getRow())
.setSeat(t.getSeat().getNumber())
.setScreenNumber(t.getScreenNumber()
);
})
// HTTP part goes here
.<BookingRequest, HttpEntity>transform(HttpEntity::new)
.handle(
Http.outboundChannelAdapter(bookingServerUrl)
.httpMethod(HttpMethod.POST)
.extractPayload(true)
.expectedResponseType(BookStatus.class)
)
// and here HTTP part ends
.handle(
Jms.outboundAdapter(responseDestinationTemplate())
)
.get();
}
And everything was OK until I utilized HTTP outbound channel adapter. I need to call simple RESTful interface and code above does it pretty well. But, following Jms.outboundAdapter(responseDestinationTemplate()) line leads to nothing, no action performes after successfull http call.
If I remove http flow part (surrounded by comments) - it works. Implemented so much stuff, almost understood and saw beauty and simplicity of integration ...aand this is it. Yet another place I got stuck in.
And here are log after success REST call:
2016-02-08 21:01:22.155 DEBUG 18209 --- [enerContainer-1] o.s.web.client.RestTemplate : POST request for "http://localhost:9052/api/book" resulted in 200 (OK)
2016-02-08 21:01:22.156 DEBUG 18209 --- [enerContainer-1] o.s.web.client.RestTemplate : Reading [class c.e.m.integration.domain.BookStatus] as "application/json;charset=UTF-8" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter#6b9469bd]
2016-02-08 21:01:22.168 DEBUG 18209 --- [enerContainer-1] i.h.o.HttpRequestExecutingMessageHandler : handler 'org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler#0' produced no reply for request Message: GenericMessage [payload=<BookingRequest(movieId=0, row=1, seat=1, screenNumber=1),{}>, headers={jms_redelivered=false, jms_replyTo=queue://statusChannel, jms_correlationId=5021291a-d4d5-47ca-b591-b6f311378688, correlationId=1d41f05a-3695-4adb-87b0-d75c17bbc3ad, id=a1fb2a2f-5d78-3183-d409-3f60aae74a20, priority=4, jms_timestamp=1454950877264, jms_messageId=ID:ins-laptop-31198-1454948247657-1:9:1:1:1, timestamp=1454950877352}]
2016-02-08 21:01:22.168 DEBUG 18209 --- [enerContainer-1] o.s.integration.channel.DirectChannel : postSend (sent=true) on channel 'inboundFlow.channel#2', message: GenericMessage [payload=<BookingRequest(movieId=0, row=1, seat=1, screenNumber=1),{}>, headers={jms_redelivered=false, jms_replyTo=queue://statusChannel, jms_correlationId=5021291a-d4d5-47ca-b591-b6f311378688, correlationId=1d41f05a-3695-4adb-87b0-d75c17bbc3ad, id=a1fb2a2f-5d78-3183-d409-3f60aae74a20, priority=4, jms_timestamp=1454950877264, jms_messageId=ID:ins-laptop-31198-1454948247657-1:9:1:1:1, timestamp=1454950877352}]
2016-02-08 21:01:22.168 DEBUG 18209 --- [enerContainer-1] o.s.integration.channel.DirectChannel : postSend (sent=true) on channel 'inboundFlow.channel#1', message: GenericMessage [payload=BookingRequest(movieId=0, row=1, seat=1, screenNumber=1), headers={jms_redelivered=false, jms_replyTo=queue://statusChannel, jms_correlationId=5021291a-d4d5-47ca-b591-b6f311378688, correlationId=1d41f05a-3695-4adb-87b0-d75c17bbc3ad, id=859af23d-214f-4400-e9cb-7d40308755cd, priority=4, jms_timestamp=1454950877264, jms_messageId=ID:ins-laptop-31198-1454948247657-1:9:1:1:1, timestamp=1454950877350}]
2016-02-08 21:01:22.168 DEBUG 18209 --- [enerContainer-1] o.s.integration.channel.DirectChannel : postSend (sent=true) on channel 'inboundFlow.channel#0', message: GenericMessage [payload={"screenNumber":1,"seat":{"row":1,"number":1},"movie":{"id":0,"name":"The Matrix"}}, headers={jms_redelivered=false, jms_replyTo=queue://statusChannel, jms_correlationId=5021291a-d4d5-47ca-b591-b6f311378688, correlationId=1d41f05a-3695-4adb-87b0-d75c17bbc3ad, id=636638ed-aec2-082e-6181-0484999fd807, priority=4, jms_timestamp=1454950877264, jms_messageId=ID:ins-laptop-31198-1454948247657-1:9:1:1:1, timestamp=1454950877331}]
No errors, no warnings at all.
Spring Integration provides two MessageHandler types: one-way - just handle message and stop. And another one is like: handle request message and produce reply to the output channel.
The first one is called like outboundChannelAdapter and with your HTTP case you just only send a POST request and don't worry about the reply.
Since the message flow is stopped on the outboundChannelAdapter no any further action is possible in the integration chain. Like in your case the next Jms.outboundAdapter won't be reached.
If you really expect the reply from your REST service you should use Http.outboundGateway instead. And your BookStatus will be sent to the JMS as you'd like by your last .handle() in the flow.