MilindaD
MilindaD

Reputation: 7653

common spring integration exception handler

Currently we have a requirement to handle exceptions in a spring integration flow.

The current solution was to handle exceptions thrown from any POJO (transformer, aggregator, service etc) by means of Aspects. And in the aspects a tweet would be sent that an exception occured. However this aspects do not cover exceptions thrown by for example the Spring Integration Flow. That is if an exception happens in an <object-to-json-transformer> or a 500 status is returned by an <int-http:outbound-gateway>.

We need a method to handle this. Currently we see that we can have the start of the flow (gateway) have an error channel attached and in this error channel send a tweet. However the issue is that we also have business logic in the service called by the error channel. So we would need to mix the tweeting (notification) and business concerns. Also this would mean that each error channel service would manually needed to be programmed to send out a tweet. So if a new error channel service is created by a new developer he/she may forget to put in the tweet code.

Is there any way that we could put a common global error handle which also gets called in addition to the flow specific error service. Then in the common global error handler code all the notification tweeting logic and any other cross cutting concerns is run. What would be the best strategy for this then.

UPDATE 1

I have come up with the following code, however it seems to give a StackOverFlowException, however when I change the payload routing channel to nullChannel the error goes away

<int:publish-subscribe-channel id="global-wire-tap-channel" />

<int:service-activator input-channel="log-channel" ref="loggerEndpointService" method="logMessageHistory" />

<int:payload-type-router input-channel="global-wire-tap-channel" default-output-channel="nullChannel">
    <int:mapping type="java.lang.Exception" channel="global-notifier-error-channel" />
</int:payload-type-router>

The stack trace is as given

java.lang.StackOverflowError
at java.lang.Class.privateGetDeclaredMethods(Class.java:2414)
at java.lang.Class.getMethod0(Class.java:2670)
at java.lang.Class.getMethod(Class.java:1603)
at org.apache.commons.logging.LogFactory.directGetContextClassLoader(LogFactory.java:825)
at org.apache.commons.logging.LogFactory$1.run(LogFactory.java:791)
at java.security.AccessController.doPrivileged(Native Method)
at org.apache.commons.logging.LogFactory.getContextClassLoader(LogFactory.java:788)
at org.apache.commons.logging.LogFactory.getFactory(LogFactory.java:383)
at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:645)
at org.springframework.messaging.support.MessageHeaderAccessor.<init>(MessageHeaderAccessor.java:51)
at org.springframework.integration.IntegrationMessageHeaderAccessor.<init>(IntegrationMessageHeaderAccessor.java:49)
at org.springframework.integration.support.MessageBuilder.<init>(MessageBuilder.java:59)
at org.springframework.integration.support.MessageBuilder.fromMessage(MessageBuilder.java:75)
at org.springframework.integration.support.DefaultMessageBuilderFactory.fromMessage(DefaultMessageBuilderFactory.java:29)
at org.springframework.integration.support.DefaultMessageBuilderFactory.fromMessage(DefaultMessageBuilderFactory.java:25)
at org.springframework.integration.history.MessageHistory.write(MessageHistory.java:76)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:76)
at org.springframework.integration.dispatcher.BroadcastingDispatcher.invokeHandler(BroadcastingDispatcher.java:160)
at org.springframework.integration.dispatcher.BroadcastingDispatcher.dispatch(BroadcastingDispatcher.java:142)
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:77)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:255)
at org.springframework.integration.channel.interceptor.WireTap.preSend(WireTap.java:128)
at org.springframework.integration.channel.AbstractMessageChannel$ChannelInterceptorList.preSend(AbstractMessageChannel.java:338)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:251)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:223)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:114)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:44)
at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:93)
at org.springframework.integration.router.AbstractMessageRouter.handleMessageInternal(AbstractMessageRouter.java:175)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:78)
at org.springframework.integration.dispatcher.BroadcastingDispatcher.invokeHandler(BroadcastingDispatcher.java:160)
at org.springframework.integration.dispatcher.BroadcastingDispatcher.dispatch(BroadcastingDispatcher.java:142)
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:77)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:255)
at org.springframework.integration.channel.interceptor.WireTap.preSend(WireTap.java:128)
at org.springframework.integration.channel.AbstractMessageChannel$ChannelInterceptorList.preSend(AbstractMessageChannel.java:338)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:251)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:223)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:114)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:44)
at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:93)
at org.springframework.integration.router.AbstractMessageRouter.handleMessageInternal(AbstractMessageRouter.java:175)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:78)
at org.springframework.integration.dispatcher.BroadcastingDispatcher.invokeHandler(BroadcastingDispatcher.java:160)
at org.springframework.integration.dispatcher.BroadcastingDispatcher.dispatch(BroadcastingDispatcher.java:142)
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:77)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:255)
at org.springframework.integration.channel.interceptor.WireTap.preSend(WireTap.java:128)
at org.springframework.integration.channel.AbstractMessageChannel$ChannelInterceptorList.preSend(AbstractMessageChannel.java:338)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:251)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:223)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:114)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:44)
at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:93)
at org.springframework.integration.router.AbstractMessageRouter.handleMessageInternal(AbstractMessageRouter.java:175)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:78)
at org.springframework.integration.dispatcher.BroadcastingDispatcher.invokeHandler(BroadcastingDispatcher.java:160)
at org.springframework.integration.dispatcher.BroadcastingDispatcher.dispatch(BroadcastingDispatcher.java:142)
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:77)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:255)
at org.springframework.integration.channel.interceptor.WireTap.preSend(WireTap.java:128)
at org.springframework.integration.channel.AbstractMessageChannel$ChannelInterceptorList.preSend(AbstractMessageChannel.java:338)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:251)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:223)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:114)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:44)
at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:93)
at org.springframework.integration.router.AbstractMessageRouter.handleMessageInternal(AbstractMessageRouter.java:175)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:78)
at org.springframework.integration.dispatcher.BroadcastingDispatcher.invokeHandler(BroadcastingDispatcher.java:160)
at org.springframework.integration.dispatcher.BroadcastingDispatcher.dispatch(BroadcastingDispatcher.java:142)
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:77)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:255)
at org.springframework.integration.channel.interceptor.WireTap.preSend(WireTap.java:128)
at org.springframework.integration.channel.AbstractMessageChannel$ChannelInterceptorList.preSend(AbstractMessageChannel.java:338)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:251)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:223)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:114)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:44)
at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:93)
at org.springframework.integration.router.AbstractMessageRouter.handleMessageInternal(AbstractMessageRouter.java:175)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:78)
at org.springframework.integration.dispatcher.BroadcastingDispatcher.invokeHandler(BroadcastingDispatcher.java:160)
at org.springframework.integration.dispatcher.BroadcastingDispatcher.dispatch(BroadcastingDispatcher.java:142)
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:77)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:255)
at org.springframework.integration.channel.interceptor.WireTap.preSend(WireTap.java:128)
at org.springframework.integration.channel.AbstractMessageChannel$ChannelInterceptorList.preSend(AbstractMessageChannel.java:338)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:251)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:223)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:114)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:44)
at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:93)
at org.springframework.integration.router.AbstractMessageRouter.handleMessageInternal(AbstractMessageRouter.java:175)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:78)
at org.springframework.integration.dispatcher.BroadcastingDispatcher.invokeHandler(BroadcastingDispatcher.java:160)
at org.springframework.integration.dispatcher.BroadcastingDispatcher.dispatch(BroadcastingDispatcher.java:142)

Apparently when I do the following it also does not work

<int:wire-tap pattern="*" channel="global-wire-tap-channel" />

<int:channel id="global-wire-tap-channel" />

<int:payload-type-router input-channel="global-wire-tap-channel" default-output-channel="nullChannel">
    <int:mapping type="java.lang.Exception" channel="global-notifier-error-channel" />
</int:payload-type-router>

However if I directly call the global-notifier-error-channel as given

<int:wire-tap pattern="*" channel="global-notifier-error-channel" />

then the notification will work

Regards, Milinda

Upvotes: 2

Views: 2372

Answers (1)

Artem Bilan
Artem Bilan

Reputation: 121262

I'd say that you go right way dividing logic to achieve loosely-coupled pronciple. That's correct that different modules (or integration flows) can have their own error handling logic and that's good that you use error-channel to catch those downstream exceptions.

I see one good solution for your global tweeting error handling. We can't use here built-in error-channel, because any custom one has precedence. But we can add an aspect for them and it is global <wire-tap> with pattern for all those target error-channels. In this case all your developers just should follow with naming convention for all their error-channels to allow that global channel-interceptor to handle messages for them.

However pay attention here, please, that WireTap processes messages in preSend. So global error-handling will be before any custom logic. In this case you may be need to write simple WireTap extension to do that in the postSend

Upvotes: 2

Related Questions