Going Bananas
Going Bananas

Reputation: 2537

JMS Inbound Gateway - error handling when reply destination queue send is not possible

We have an EIP flow which uses annotation-based spring:4.2.x APIs, spring-integration:4.2.x APIs and spring-integration-java-dsl:1.1.0 APIs to receive messages from a Websphere MQ Queue, do some processing and finally return responses to another Websphere MQ Queue. For this flow, we are using a JMS Inbound Gateway to synchronously receive messages from one queue, process them and send the responses back to another queue.

The JMS Inbound Gateway is configured with an errorChannel so that RuntimeExceptions are routed to it (this works fine). However during tests, when we purposely apply a PUT_INHIBIT on the flow's response Websphere MQ queue (i.e. to cause the flow to be unable to send responses back to the reply queue), the spring logs show the following WARNING log message:

WARN ... - Execution of JMS message listener failed, and no ErrorHandler has been set. javax.jms.JMSException: MQJMS2007: failed to send message to MQ queue.

We know we can remove that WARNING log by configuring an ErrorHandler on the MLC itself but, the reason this is causing us problems is that when we route a response back, we actually route using a .routeToRecipients() call with .setIgnoreFailures(false) and two recipients - the first recipient routing to the JMS Inbound Gateway's replyChannel and the second routing to a post-send flow so that we can do DB updates, etc. The idea here being that if the first recipient send fails (i.e. when the response queue is not available), the post-send flow doesn't execute but instead an error handling flow executes instead (e.g. errorChannel flow). But in the described error scenario, we see the warning log, and the flow's post-send flow still executes instead of the errorChannel's flow...

It is as though, at this point, the JMS Inbound Gateway's errorChannel no longer applies. Is this correct? And is this intended behaviour? And if it is, does this mean that we should use Inbound/Outbound Adapters instead of an Inbound Gateway for our response post-send intent?

JMS MLC Configuration:

@Bean( destroyMethod = "shutdown")
public DefaultMessageListenerContainer serviceMLC() throws Exception {

    DefaultMessageListenerContainer mlc = new DefaultMessageListenerContainer();
    mlc.setAutoStartup(false);
    mlc.setConnectionFactory(serviceCCF);
    mlc.setDestination(requestMqQueue);
    mlc.setAcceptMessagesWhileStopping(false);
    return mlc;
}

JMS Inbound Gateway Configuration:

@Bean
public IntegrationFlow serviceFlow() {

    return IntegrationFlows
            .from(Jms
                    .inboundGateway(serviceMLC)
                    .autoStartup(true)
                    .defaultReplyDestination(responseMqQueue)
                    .replyChannel(responseOutCh)
                    .replyTimeout(180000)
                    .correlationKey("JMSCorrelationID")
                    .errorChannel(serviceErrorCh)
                    )
            .channel(serviceInCh)
            .get();
}

Upvotes: 1

Views: 1170

Answers (1)

Gary Russell
Gary Russell

Reputation: 174769

Yes; the gateway doesn't work that way.

When you send the reply to the gateway, it is queued in the gateway until the thread returns to the gateway; at which time, the reply is picked up and sent. So, the failure to send does not occur until later (after your second recipient flow is invoked).

Yes, to do what you want, you should use channel adapters instead because the failure will run directly on the calling thread.

Upvotes: 1

Related Questions