Announcement Announcement Module
Collapse
No announcement yet.
Error-channel and nested gateway calls Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Error-channel and nested gateway calls

    I've searched the forums and the documentation but could not find any answer to my question there. We're using Spring Integration 2.0.5.RELEASE.

    Anywhere an exception occurs in our application, we want the exception to go to the "transform-error-to-response" channel where it is transformed into a proper response message and returned to the user.

    To make this possible we set the error-channel on the very first gateway call used for incoming requests, and then never set an error-channel further down the flow like below:

    Code:
    	<chain input-channel="incoming-requestChannel">
    		<gateway request-channel="service1-channel" error-channel="transform-error-to-response" />
    	</chain>
    
    
    	<chain id="Service1-chain" input-channel="service1-channel" >
    		
    		<gateway request-channel="performValidation-Channel" />
    
    		<header-enricher>
    			<header name="request" expression="payload" />
    		</header-enricher>
    						
    		<recipient-list-router apply-sequence="true" >
    			<recipient channel="call-foo-service" />
    			<recipient channel="call-bar-service" />
    		</recipient-list-router>
    	</chain>
    
    	<chain id="performValidation-chain" input-channel="performValidation-Channel" > 
    		<service-activator ref="inputValidator" ></service-activator>
    	</chain>
    
    	<chain input-channel="call-foo-service" output-channel="handle-foo-result">
    		<gateway request-channel="foo-channel">
    	</chain>
    However, when an exception occurs in the flow of "foo-channel", the exception does not go to the "transform-error-to-response" channel defined as error channel in the first error call. Instead the flow goes to some other, unknown error channel (not the default errorChannel either).

    To get the error to reach the "transform-error-to-response" channel as intended, we have to add an errorChannel to the gateway call to "foo-channel" which has a call to a service activator which simply re-throws the exception:

    Code:
    	<chain input-channel="call-foo-service" output-channel="handle-foo-result">
    		<gateway request-channel="foo-channel" error-channel="propagate-exception">
    	</chain>
    
    	<chain input-channel="propagate-exception">
    		<service-activator method="propagateErrorMessage">
    			<beans:bean class="com.example.errorhandling.ErrorPropagator"/>
    		</service-activator>
    	</chain>
    Code:
    public class ErrorPropagator {
    
    	public void propagateErrorMessage(Message<MessagingException> exceptionMsg) throws MessagingException{	
    		MessagingException msgExp = exceptionMsg.getPayload();
    		throw msgExp;
    	}	
    }
    So my question is: Why is this extra error-channel which re-throws the error needed? My understanding was that since the error-channel is initially set to "transform-error-to-response" and then never overwritten, this would be the channel used when any exception occurs downstream.

  • #2
    I have done some experimenting with moving and removing components and found that this seems to be related to the usage of chains.

    I have been able to reduce the config for when this error occurs to:

    Code:
    	<chain input-channel="incoming-requestChannel">
    		<gateway request-channel="service1-channel" error-channel="transform-error-to-response" />
    	</chain>
    
    	<chain id="Service1-chain" input-channel="service1-channel" >
    		<gateway request-channel="call-foo-service" />
    	</chain>
    
    	<chain input-channel="call-foo-service" />
    		<gateway request-channel="foo-channel">
    	</chain>
    If an exception occurs after the call to foo-channel here, the error is not thrown to "transform-error-to-response".
    However, if we bypass the final chain and call "foo-channel" straight from the "Service1-chain", the error goes to "transform-error-to-response" as expected:
    Code:
    	<chain input-channel="incoming-requestChannel">
    		<gateway request-channel="service1-channel" error-channel="transform-error-to-response" />
    	</chain>
    
    	<chain id="Service1-chain" input-channel="service1-channel" >
    		<gateway request-channel="foo-channel" />
    	</chain>

    I still don't understand why this happens though.

    Comment


    • #3
      Hello

      I've written some test-case based on your issue:
      Config:
      HTML Code:
      <channel id="input"/>
      
      <channel id="chain1Channel"/>
      
      <channel id="chain2Channel"/>
      
      <channel id="serviceChannel"/>
      
      <channel id="errorChannel"/>
      
      <chain input-channel="input">
      	<gateway request-channel="chain1Channel" error-channel="errorChannel"/>
      </chain>
      
      <chain input-channel="chain1Channel">
      	<gateway request-channel="chain2Channel"/>
      </chain>
      
      <chain input-channel="chain2Channel">
      	<gateway request-channel="serviceChannel"/>
      </chain>
      
      <payload-type-router input-channel="serviceChannel" resolution-required="true">
      	<mapping type="java.lang.String" channel="fooChannel"/>
      </payload-type-router>
      
      <outbound-channel-adapter channel="errorChannel">
      	<beans:bean class="org.springframework.integration.handler.ChainExceptionPropagationTests$TestErrorHandler"/>
      </outbound-channel-adapter>
      Test Class
      Code:
      @ContextConfiguration
      @RunWith(SpringJUnit4ClassRunner.class)
      public class ChainExceptionPropagationTests {
      
      	@Autowired
      	MessageChannel input;
      
      	@Test
      	public void testChainExceptionPropagation() {
      		try {
      			this.input.send(MessageBuilder.withPayload(1).build());
      		}
      		catch (Exception e) {
      			assertEquals("intentional", e.getCause().getMessage());
      		}
      	}
      
      	private static class TestErrorHandler implements MessageHandler {
      
      		@Override
      		public void handleMessage(Message<?> message) throws MessagingException {
      			throw new RuntimeException("intentional");
      		}
      	}
      
      }
      But if I made some of the 'chain1Channel' or 'chain2Channel' as queue my test hangs.
      So, maybe do you have similar channel config?
      By default asynchronous message-flows send their Exceptions into default "errorChannel": http://static.springsource.org/sprin...e-errorhandler

      So, WDYT?

      Take care,
      Artem

      Comment


      • #4
        Originally posted by Cleric View Post
        But if I made some of the 'chain1Channel' or 'chain2Channel' as queue my test hangs.
        So, maybe do you have similar channel config?
        By default asynchronous message-flows send their Exceptions into default "errorChannel": http://static.springsource.org/sprin...e-errorhandler

        So, WDYT?

        Take care,
        Artem
        Hi Artem,

        Thank you for your reply.

        Yes, we do have a similar config. Our "incoming-requestChannel" has a ThreadPoolTaskExecutor attached to it:

        Code:
        <beans:bean id="taskExecutor"
        class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
        <beans:property name="corePoolSize" value="50"/> 
        <beans:property name="maxPoolSize" value="200" />
        <beans:property name="queueCapacity" value="1" />
        </beans:bean>
        
        <channel id="incoming-requestChannel">
        <dispatcher task-executor="taskExecutor" />
        </channel>
        You say that the default behavior for asynch message flows is to send their exceptions to the "errorChannel", but this doesn't seem to be the case here. I've tried attaching custom error-handling to the "errorChannel", but the exception did not reach that flow.

        I also thought that once we explicitly stated an error-channel property, as we do in the "incoming-requestChannel" chain, the default behavior will not be applied anymore.
        Last edited by anwi; Oct 1st, 2012, 05:14 AM.

        Comment


        • #5
          Hi!

          H-m-m...
          Can you show channels' config for this one:
          <chain input-channel="incoming-requestChannel">
          <gateway request-channel="service1-channel" error-channel="transform-error-to-response" />
          </chain>

          <chain id="Service1-chain" input-channel="service1-channel" >
          <gateway request-channel="call-foo-service" />
          </chain>

          <chain input-channel="call-foo-service" />
          <gateway request-channel="foo-channel">
          </chain>
          I need to know: who are they?

          Comment


          • #6
            Hi,

            I made a mistake in my previous post which I have now edited. The task-executor is attached to the "incoming-requestChannel" and nothing else.

            I'm not sure what more info I can give you. incoming-requestChannel is the only channel explicitly defined. All other channels are only mentioned in the chains above and have no separate definition.

            As for "foo-channel", it is a complex flow but I still get this error if I just change it to point to a Service Activator with a method that just throws an exception.

            If you need any more information, please let me know.

            Comment


            • #7
              Does your config is approximated to this one:
              HTML Code:
              <task:executor id="executor" pool-size="50-200" queue-capacity="1"/>
              
              	<channel id="input">
              		<dispatcher task-executor="executor"/>
              	</channel>
              
              	<channel id="errorChannel1"/>
              
              	<chain input-channel="input">
              		<gateway request-channel="chain1Channel" error-channel="errorChannel1"/>
              	</chain>
              
              	<chain input-channel="chain1Channel">
              		<gateway request-channel="chain2Channel"/>
              	</chain>
              
              	<chain input-channel="chain2Channel">
              		<gateway request-channel="serviceChannel"/>
              	</chain>
              
              	<payload-type-router input-channel="serviceChannel" resolution-required="true">
              		<mapping type="java.lang.String" channel="fooChannel"/>
              	</payload-type-router>
              
              	<outbound-channel-adapter channel="errorChannel1">
              		<beans:bean class="org.springframework.integration.handler.ChainExceptionPropagationTests$TestErrorHandler"/>
              	</outbound-channel-adapter>
              
              	<logging-channel-adapter channel="errorChannel" level="FATAL"/>
              For me it's working excelent:
              1. <payload-type-router> throws Exception about "channel resolution"
              2. My ChainExceptionPropagationTests$TestErrorHandler rethrows a intentional Exception
              3. <ogging-channel-adapter> logs a FATAL about the last one

              Now I really don't understand what's going on...
              Can you switch to the latest Spring Integration version?

              Comment


              • #8
                I have not had a chance to read the whole post in details, but I see you are asking about nested gateways with respect of errors going to the appropriate error-channel.
                I spoke about this use case in the last year's SpringOne and I'd suggest to look at the following sample https://github.com/olegz/s12gx.2011/...n/segmentation

                Let us know

                Comment


                • #9
                  Hello,

                  I am no longer part of the project, so I'm afraid I can't test with a new version of Spring Integration or provide further testing.

                  Our config was pretty much identical to the one provided by Cleric, but we did not get the same behavior. Comparing with Cleric's config our ChainExceptionPropagationTests$TestErrorHandler was never invoked because the error for some reason did not route to "errorChannel1".

                  Perhaps we had configured something incorrectly or perhaps there was an issue with our version of Spring Integration. Either way I am content with knowing that the behavior we saw was not intended.

                  Thank you for your help!
                  Regards
                  Andreas

                  Comment

                  Working...
                  X