user1053031
user1053031

Reputation: 747

Spring Integration. How to catch the Custom exception?

It seems i don't understand some underlying concepts about custom Exceptions handling in Spring Integration(

I need to intercept some of my RuntimeException-derived custom exceptions (thrown from some my Java method) and depending of it's type route the app execution flow to some other route.

I use the Spring Integration version 4.3.10.RELEASE.

To do this i declare the int:exception-type-router like this:

<int:exception-type-router input-channel="errorChannel" default-output-channel="nullChannel">
        <int:mapping exception-type="com.surr.exception.SurrRoutingException"
                     channel="handleRedirectChannel"/>
        <int:mapping exception-type="com.surr.exception.SurrFatalException"
                     channel="surrChannelMain"/>
        <!-- some more mappings -->
</int:exception-type-router>

Channel declaration sample:

<int:channel id="handleRedirectChannel"
     datatype="com.surr.exception.SurrRoutingException">
      <int:queue/>
</int:channel>

After my Exception throwing i cannot step into related channels. What i'm doing wrong? Maybe i've missed smth in the app initial setup?

Thanks a lot for any assist.

Update After notes from Artem i made some changes described below:

  1. Introduced additional error channel:
<int:channel id="errorChannel1">
        <int:queue capacity="500"/>
</int:channel>
  1. As the very 1st statement in my message processing chain overrode the 'errorChannel' header:
<int:header-enricher>
            <int:header name="errorChannel" value="errorChannel1"/>
</int:header-enricher>
  1. Modified the 'int:exception-type-router':
<int:exception-type-router input-channel="errorChannel1" default-output-channel="nullChannel">
        <int:mapping exception-type="java.lang.Throwable"
                     channel="handleRedirectChannel"/>
        <int:mapping exception-type="java.lang.RuntimeException"
                     channel="handleRedirectChannel"/>
        <int:mapping exception-type="com.surr.exception.SurrRoutingException"
                     channel="handleRedirectChannel"/>
        <int:mapping exception-type="com.surr.exception.SurrFatalException"
                     channel="surrChannelMain"/>
</int:exception-type-router>
  1. Changed the declarations of the recipient channels:
<int:channel id="handleRedirectChannel">
     <int:queue capacity="50"/>
</int:channel>

<int:channel id="surrChannelMain">
     <int:queue capacity="50"/>
</int:channel>
  1. In my test began to 'listen' the 'errorChannel1' along w/ the 'handleRedirectChannel' channels

So far there is no any tracks of my thrown Exceptions. I suspect there are some more rules exist to catch the Exception but can't figure them out

One more update I've issued my exception manually using MessageBuilder (MessageBuilder.withPayload(new MyExceptionObjectWithNeededArguments).build()) and sent it to the 'errorChannel1'. Still no effect(

Stack trace

2021-02-17 23:03:48,742  INFO [   task-scheduler-20             ] [] !! IntentsService.prepareMessages
com.azoft.fakturachat.surrogate.exception.SurrogateRoutingException: Got empty intent description by scenario: [default] and tip: [some_unknown_intent]
    at com.azoft.fakturachat.surrogate.IntentsService.fetchIntentDescription(IntentsService.java:84) ~[main/:?]
    at com.azoft.fakturachat.surrogate.IntentsService.lambda$prepareMessages$0(IntentsService.java:58) ~[main/:?]
    at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193) ~[?:1.8.0_172]
    at java.util.Collections$2.tryAdvance(Collections.java:4717) ~[?:1.8.0_172]
    at java.util.Collections$2.forEachRemaining(Collections.java:4725) ~[?:1.8.0_172]
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) ~[?:1.8.0_172]
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) ~[?:1.8.0_172]
    at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) ~[?:1.8.0_172]
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[?:1.8.0_172]
    at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) ~[?:1.8.0_172]
    at com.azoft.fakturachat.surrogate.IntentsService.prepareMessages(IntentsService.java:59) ~[main/:?]
    at com.azoft.fakturachat.surrogate.IntentsService$$FastClassBySpringCGLIB$$d29d5141.invoke(<generated>) ~[main/:?]
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:721) ~[spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:85) ~[spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at com.azoft.fakturachat.aspect.LoggingAspect.logMethod(LoggingAspect.java:31) [main/:?]
    at sun.reflect.GeneratedMethodAccessor131.invoke(Unknown Source) ~[?:?]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_172]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_172]
    at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:629) [spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:618) [spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70) [spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) [spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) [spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) [spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:656) [spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at com.azoft.fakturachat.surrogate.IntentsService$$EnhancerBySpringCGLIB$$9cfa94da.prepareMessages(<generated>) [main/:?]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_172]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_172]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_172]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_172]
    at org.springframework.expression.spel.support.ReflectiveMethodExecutor.execute(ReflectiveMethodExecutor.java:113) [spring-expression-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.expression.spel.ast.MethodReference.getValueInternal(MethodReference.java:129) [spring-expression-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.expression.spel.ast.MethodReference.access$000(MethodReference.java:49) [spring-expression-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.expression.spel.ast.MethodReference$MethodValueRef.getValue(MethodReference.java:347) [spring-expression-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:88) [spring-expression-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.expression.spel.ast.SpelNodeImpl.getTypedValue(SpelNodeImpl.java:131) [spring-expression-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:330) [spring-expression-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.integration.util.AbstractExpressionEvaluator.evaluateExpression(AbstractExpressionEvaluator.java:169) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.util.AbstractExpressionEvaluator.evaluateExpression(AbstractExpressionEvaluator.java:128) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.handler.ExpressionEvaluatingMessageProcessor.processMessage(ExpressionEvaluatingMessageProcessor.java:72) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.transformer.support.ExpressionEvaluatingHeaderValueMessageProcessor.processMessage(ExpressionEvaluatingHeaderValueMessageProcessor.java:71) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.transformer.HeaderEnricher.transform(HeaderEnricher.java:119) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.transformer.MessageTransformingHandler.handleRequestMessage(MessageTransformingHandler.java:89) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:109) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:127) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.handler.MessageHandlerChain.handleMessageInternal(MessageHandlerChain.java:110) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:127) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.dispatcher.AbstractDispatcher.tryOptimizedDispatch(AbstractDispatcher.java:116) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:148) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:121) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:89) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:423) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:373) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:115) [spring-messaging-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:45) [spring-messaging-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:105) [spring-messaging-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.integration.router.AbstractMessageRouter.handleMessageInternal(AbstractMessageRouter.java:194) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:127) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.handler.MessageHandlerChain$1.send(MessageHandlerChain.java:129) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:115) [spring-messaging-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:45) [spring-messaging-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:105) [spring-messaging-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.integration.handler.AbstractMessageProducingHandler.sendOutput(AbstractMessageProducingHandler.java:292) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.handler.AbstractMessageProducingHandler.produceOutput(AbstractMessageProducingHandler.java:212) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.handler.AbstractMessageProducingHandler.sendOutputs(AbstractMessageProducingHandler.java:129) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:115) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:127) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.handler.MessageHandlerChain$1.send(MessageHandlerChain.java:129) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:115) [spring-messaging-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:45) [spring-messaging-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:105) [spring-messaging-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.integration.handler.AbstractMessageProducingHandler.sendOutput(AbstractMessageProducingHandler.java:292) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.handler.AbstractMessageProducingHandler.produceOutput(AbstractMessageProducingHandler.java:212) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.handler.AbstractMessageProducingHandler.sendOutputs(AbstractMessageProducingHandler.java:129) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:115) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:127) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.handler.MessageHandlerChain$1.send(MessageHandlerChain.java:129) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:115) [spring-messaging-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:45) [spring-messaging-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:105) [spring-messaging-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.integration.handler.AbstractMessageProducingHandler.sendOutput(AbstractMessageProducingHandler.java:292) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.handler.AbstractMessageProducingHandler.produceOutput(AbstractMessageProducingHandler.java:212) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.handler.AbstractMessageProducingHandler.sendOutputs(AbstractMessageProducingHandler.java:129) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:115) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.handler.DelayHandler.doReleaseMessage(DelayHandler.java:376) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.handler.DelayHandler.access$500(DelayHandler.java:83) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.handler.DelayHandler$ReleaseMessageHandler.handleMessage(DelayHandler.java:470) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.handler.DelayHandler.releaseMessage(DelayHandler.java:368) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.handler.DelayHandler.access$100(DelayHandler.java:83) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.integration.handler.DelayHandler$1.run(DelayHandler.java:328) [spring-integration-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) [spring-context-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:1.8.0_172]
    at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:1.8.0_172]
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) [?:1.8.0_172]
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) [?:1.8.0_172]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_172]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_172]
    at java.lang.Thread.run(Thread.java:748) [?:1.8.0_172]
2021-02-17 23:03:48,751  INFO [   task-scheduler-20             ] [] <- IntentsService.prepareMessages, procTime=306

The 'errorChannel1' channel was introduced only to test this issue. There is no other consumer(s) except this 'exception-type-router'

Exception is 'thrown' in the following way:

SurrRoutingException ex1 = new SurrRoutingException(
                MessageFormat.format("Failed to find intent description by scenario: [{0}] and tip: [{1}]",
                    scenario, tip), context);
errorChannel.send(MessageBuilder.withPayload(ex1).build());

Error channel declaration:

private final QueueChannel errorChannel;

@Autowired
public IntentsService(@Qualifier("errorChannel1") QueueChannel errorChannel) 
{
        this.errorChannel = errorChannel;
}

Upvotes: 0

Views: 1107

Answers (2)

user1053031
user1053031

Reputation: 747

I've returned to this issue again. Didn't make a sample project yet but found some info in docs. "SI error handling": "The most important thing to understand here is that the messaging-based error handling applies only to exceptions that are thrown by a Spring Integration task that is executing within a TaskExecutor. This does not apply to exceptions thrown by a handler that operates within the same thread as the sender (for example, through a DirectChannel as described earlier in this section)".

Maybe here is the problem? My app logic is splitted between different chains and routes and maybe some of them are executed not within TaskExecutor and because of it the global interception is not working? i assume that a single, global-scope interceptor per the whole application is not enough. I'm going to verify this assumption. Thanks!

Upvotes: 0

Artem Bilan
Artem Bilan

Reputation: 121560

I think your confuse is because an <int:exception-type-router> can deal with stack trace to track an expected exception down, but datatype on the channel is exact type of the payload.

See docs for more info:

https://docs.spring.io/spring-integration/docs/current/reference/html/message-routing.html#router-implementations-exception-router

https://docs.spring.io/spring-integration/docs/current/reference/html/core.html#channel-datatype-channel

I would say you don't need a datatype for that handleRedirectChannel since you use it only from that router. The point of datatype is really to restrict producers for this channel which make sense when our application is complex enough and may work even in distributed state when we can't control producers. It doesn't look like a case for your exception router...

Upvotes: 1

Related Questions