Announcement Announcement Module
Collapse
No announcement yet.
Regarding exception in downstream from a Executor Channel.. Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Regarding exception in downstream from a Executor Channel..

    Hi

    I've the following gateway configuration defined:

    Code:
    	<!--  Gateway -->
    	<int:gateway id="ersOrchestrationSvcGateway"
    				 service-interface="com.bnym.ecs.report.service.orchestration.gateway.ERSOrchestrationSvcGateway"
    				 error-channel="globalExceptionHandlerChannel" 
    				 default-reply-channel="ersOrcSvcGatewayReplyChannel">
    
    		<int:method name="processCallback" request-channel="ersServiceCallbackRcvChannel">
    			<int:header name="isVoid" value="true"/>
    		</int:method>
    
    	</int:gateway>
    I need to return the caller thread once the message is placed on the "request-channel" and process the message as part of separate thread. Therefore, I've defined the the "request-channel" as an executor channel

    Code:
    	
            <int:channel id="ersServiceCallbackRcvChannel">
    		<int:dispatcher task-executor="threadPoolTaskExecutor"/>	
    	</int:channel>
    So this means the processing of a message on "ersServiceCallbackRcvChannel" will be done by a thread separate than the caller thread.

    The message consumer of this channel is a long downstream of chains that processes the message.

    The issue I'm facing is : If there is a RuntimeException in the downstream that is reading this channel, the exception is *not* thrown to the "error-channel" defined at my gateway. So any clean-up processing that I need to do with failed message is not happening.

    How can I get this fixed so that the any exception on the executor thread also lands up on gateway's "error-channel" ?

    Thanks
    LB
    Last edited by lbvirgo; Jul 19th, 2013, 05:04 AM.

  • #2
    Hi!

    Right, it doesn't work, because your loss is within another Thread.
    However there is a trick for similar cases:
    HTML Code:
    <bean id="taskExecutor" class="org.springframework.integration.util.ErrorHandlingTaskExecutor">
                <constructor-arg name="executor" ref="threadPoolTaskExecutor"/>
                <constructor-arg name="errorHandler">
    		<bean class="org.springframework.integration.channel.MessagePublishingErrorHandler">
    			<property name="defaultErrorChannel" ref="globalExceptionHandlerChannel"/>
    		</bean>
    	</constructor-arg>
    </bean>
    And inject it to your ExecutorChannel.

    Cheers,
    Artem

    Comment


    • #3
      Thanks Artem for the suggestion.

      A quick clarification - the exception that will landup on "error-channel" will be a MessagingException ?
      The reason I ask it is because I've a transformer reading the "error-channel" and under it I'm doing

      failedMsg = ((MessagingException) message.getPayload()).getFailedMessage();

      So just need to be sure that I do not end up getting a ClassCastException.

      Best Regards
      LB

      Comment


      • #4
        the exception that will landup on "error-channel" will be a MessagingException ?
        If your RuntimeException is thrown within some SI-component (e.g. <service-activator>), yes it will be wrapped with MessagingException: https://github.com/SpringSource/spri...ndler.java#L75

        Comment


        • #5
          Just realized that the property "defaultErrorChannel" of MessagePublishingErrorHandler refer to a MessageChannel type

          So I'm being forced to define this channel through <int:channel> element. Earlier on SI did not complain even when I did not explicitly defined this channel but Spring Beans container does complain (and that makes sense).

          Code:
          Cannot resolve reference to bean 'globalExceptionHandlerChannel' while setting bean property 'defaultErrorChannel'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'globalExceptionHandlerChannel' is defined
          I'm only afraid that I may again end up with my old issue of global interceptor not getting invoked when defining the "error-channel" explicitly.

          http://forum.springsource.org/showth...uot-at-Gateway
          Last edited by lbvirgo; Jul 19th, 2013, 08:05 AM.

          Comment


          • #6
            I'm being forced to define this channel through <int:channel> element
            Well. You can precede your ExecutorChannel with <header-enricher> and add your 'error-channel' as a String literal to concrate header - 'error-channel'.
            And further, if you'll tale a look into MessagePublishingErrorHandler source code, you'll see that the last one does fall-back to the 'defaultErrorChannel' only when there is no specified header in the failed Message:
            https://github.com/SpringSource/spri...dler.java#L115

            Comment


            • #7
              You can precede your ExecutorChannel with <header-enricher> and add your 'error-channel' as a String literal to concrate header - 'error-channel'.
              Sorry but I do not understand this. Can you pls elaborate ?

              LB

              Comment


              • #8
                Sorry but I do not understand this. Can you pls elaborate ?
                Something like this:
                HTML Code:
                <int:gateway id="ersOrchestrationSvcGateway"
                				 service-interface="com.bnym.ecs.report.service.orchestration.gateway.ERSOrchestrationSvcGateway"
                				 error-channel="globalExceptionHandlerChannel" 
                				 default-reply-channel="ersOrcSvcGatewayReplyChannel">
                
                		<int:method name="processCallback" request-channel="ersServiceCallbackRcvChannel">
                			<int:header name="isVoid" value="true"/>
                		</int:method>
                
                	</int:gateway>
                
                <int:header-enricher input-cahnnel="ersServiceCallbackRcvChannel" output-channel="processErsServiceCallbackRcvChannel">
                      <int:error-channel value="globalExceptionHandlerChannel"/>
                </int:header-enricher>
                
                <int:channel id="processErsServiceCallbackRcvChannel">
                		<int:dispatcher task-executor="threadPoolTaskExecutor"/>	
                	</int:channel>
                From other side: I didn't understand what you've meant.
                How do you live without channels at all? I'd say it's bad practice.

                Comment


                • #9
                  Thanks for clarifying Cleric.

                  Let me try out the suggestion you mentioned.

                  Also, I've great respect for English language but sometimes it becomes difficult to understand it due to various "flavors" it has.

                  Sorry again, but do not understand your below statement :

                  How do you live without channels at all? I'd say it's bad practice.

                  Comment


                  • #10
                    Hi!

                    How do you live without channels at all? I'd say it's bad practice.
                    As I understood you correctly:
                    Earlier on SI did not complain even when I did not explicitly defined this channel
                    you don't declare channels directly:
                    HTML Code:
                    <channel id="foo"/>
                    Maybe you so lazy, or you rely that Spring Integration so smart to do a lot of work for you . But as you see there are may be some cases where you get issues. And from other side do not declare channels you lose some flexibility, where you may change a type of channel at any time. And, of course, in this case you can add interceptors to specific channel without anxiety of other your channels.

                    Does it explain a bit what I meant?

                    Comment


                    • #11
                      Does it explain a bit what I meant?
                      A lot !

                      Maybe you so lazy, or you rely that Spring Integration so smart to do a lot of work for you
                      Indeed I was but I'll put all blame on the f/w for making me doing that; would have been great if they had put on a schema validation to declare channels before using them !

                      A quick thing I just noticed : In your earlier post when you provided a sample code for <header-enricher> as below

                      Code:
                      <int:header-enricher input-cahnnel="ersServiceCallbackRcvChannel" output-channel="processErsServiceCallbackRcvChannel">
                            <int:error-channel value="globalExceptionHandlerChannel"/>
                      </int:header-enricher>
                      Mentioning input-cahnnel was a typo OR you really meant to spell that way ? (i.e., "cahnnel" instead of "channel") ?

                      The reason I ask this is because the IDE I'm using (NTS - Netxstudio Tool Suite) is also (strangely !) suggesting the same spelling that you mentioned in your post.
                      Pls find attached the scrn shot to understand what I mean.

                      Attachment

                      If you see the scrn shot, though I typed in as "input-channel", the suggested attribute is "input-cahnnel".

                      Can this be an issue with the IDE I'm using ?

                      Just to confirm if its the case with other elements or not, I tried on the IDE "suggested" attribute names for other components (chain, service-activator, etc). For those components, IDE suggested correct spelling (i.e., suggested "input-channel" and NOT "input-cahnnel").

                      Regards
                      LB
                      Attached Files

                      Comment


                      • #12

                        Don't worry it really was my typo. Sorry.
                        And of course, don't rely on IDE fully. You always can take a look into XSD of mentioned elements and attributes.

                        Comment


                        • #13
                          Thanks for responding.

                          Just to update on the actual issue of this post, the suggestion of <header-enricher> did not work. I get following exception:

                          Code:
                          SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
                          org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'taskExecutor' defined in ServletContext resource [/WEB-INF/spring/ersOrchestration-spring-config-beans.xml]: Cannot create inner bean 'org.springframework.integration.channel.MessagePublishingErrorHandler#685f1ba8' of type [org.springframework.integration.channel.MessagePublishingErrorHandler] while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.integration.channel.MessagePublishingErrorHandler#685f1ba8' defined in ServletContext resource [/WEB-INF/spring/ersOrchestration-spring-config-beans.xml]: Cannot resolve reference to bean 'globalExceptionHandlerChannel' while setting bean property 'defaultErrorChannel'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'globalExceptionHandlerChannel' is defined
                          	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:282)
                          	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:121)
                          	at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:629)
                          	at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:148)
                          	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1049)
                          	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:953)
                          	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:490)
                          	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461)
                          	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
                          	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
                          	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
                          	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
                          	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:626)
                          	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
                          	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
                          	at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:255)
                          	at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:199)
                          	at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:45)
                          	at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4797)
                          	at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5291)
                          	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
                          	at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)
                          	at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)
                          	at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:633)
                          	at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:977)
                          	at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1655)
                          	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
                          	at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
                          	at java.util.concurrent.FutureTask.run(FutureTask.java:138)
                          	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
                          	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
                          	at java.lang.Thread.run(Thread.java:662)
                          Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.integration.channel.MessagePublishingErrorHandler#685f1ba8' defined in ServletContext resource [/WEB-INF/spring/ersOrchestration-spring-config-beans.xml]: Cannot resolve reference to bean 'globalExceptionHandlerChannel' while setting bean property 'defaultErrorChannel'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'globalExceptionHandlerChannel' is defined
                          	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:329)
                          	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:107)
                          	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1391)
                          	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1132)
                          	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:522)
                          	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461)
                          	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:271)
                          	... 31 more
                          Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'globalExceptionHandlerChannel' is defined
                          	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:568)
                          	at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1099)
                          	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:278)
                          	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
                          	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:323)
                          	... 37 more
                          The spring "bean" container is again trying to look out for a <channel> named "globalExceptionHandlerChannel".

                          Following are the configurations I'd done as was suggested earlier :
                          Code:
                          	<!--  Gateway -->
                          	<int:gateway id="ersOrchestrationSvcGateway"
                          				 service-interface="com.bnym.ecs.report.service.orchestration.gateway.ERSOrchestrationSvcGateway"
                          				 error-channel="globalExceptionHandlerChannel"
                          				 default-reply-channel="ersOrcSvcGatewayReplyChannel">
                          
                          
                          		<int:method name="processCallback" request-channel="ersServiceCallbackRcvChannel">
                          			<int:header name="isVoid" value="true"/>
                          		</int:method>
                          
                          	</int:gateway>
                          
                          	<int:header-enricher input-channel="ersServiceCallbackRcvChannel" output-channel="processErsServiceCallbackRcvChannel">
                                <int:error-channel value="globalExceptionHandlerChannel"/>
                          	</int:header-enricher>
                          
                          	<int:channel id="processErsServiceCallbackRcvChannel">
                          		<int:dispatcher task-executor="taskExecutor"/>	
                          	</int:channel>
                          
                          	<int:bridge input-channel="processErsServiceCallbackRcvChannel" output-channel="ersServiceResRcvPostValidationChannel" />
                          and my bean config for thread executor as below:

                          Code:
                          	<bean id="taskExecutor" class="org.springframework.integration.util.ErrorHandlingTaskExecutor">
                          		<constructor-arg name="executor" ref="threadPoolTaskExecutor"/>
                          		<constructor-arg name="errorHandler">
                          			<bean class="org.springframework.integration.channel.MessagePublishingErrorHandler">
                          				<property name="defaultErrorChannel" ref="globalExceptionHandlerChannel"/>
                          			</bean>
                          		</constructor-arg>
                          	</bean>
                          	
                          	<bean id="threadPoolTaskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
                          		<property name="corePoolSize" value="5" />
                          		<property name="maxPoolSize" value="10" />
                          		<property name="queueCapacity" value="25" />
                          	</bean>
                          This is really annoying .
                          I want my executor channel thread's exception to land on Gateway's error-channel and in doing so I'm "forced" to declare the channel explicitly. On other hand if I declare it explicitly, my global interceptors are not getting invoked.

                          And its too late for me in my project lifecycle to do business logic changes with Global Interceptors code (as was suggested by Gary in my post http://forum.springsource.org/showth...uot-at-Gateway).
                          I know that the minimum effort workaround will be to replace interceptors with service-activators, but this is really defeating the design that we have already proposed to our Architect Group !

                          Regards
                          LB
                          Last edited by lbvirgo; Jul 22nd, 2013, 07:19 AM.

                          Comment


                          • #14
                            Everything looks good.
                            But you didn't understand me again.
                            If you declare <header-enricher> with 'error-channel' header, there is no reason to declare 'defaultErrorChannel' on 'MessagePublishingErrorHandler' bean.
                            So, now your config should be like this:
                            HTML Code:
                            <bean id="taskExecutor" class="org.springframework.integration.util.ErrorHandlingTaskExecutor">
                            		<constructor-arg name="executor" ref="threadPoolTaskExecutor"/>
                            		<constructor-arg name="errorHandler">
                            			<bean class="org.springframework.integration.channel.MessagePublishingErrorHandler"/>
                            		</constructor-arg>
                            </bean>
                            And I suggested you to take a look into source code and I shown you where to find - https://github.com/SpringSource/spri...dler.java#L115, to understand how it works.

                            Try one more time, please

                            Comment


                            • #15
                              You know what Cleric - You are the "chosen" one !

                              It did work ! Many thanks !!

                              And I suggested you to take a look into source code and I shown you where to find -
                              My bad, sometimes I just seem to overlook at simple things !

                              Best Regards
                              LB

                              Comment

                              Working...
                              X