Spring Integration
  1. Spring Integration
  2. INT-2321

Spring Integration - Chain Processing Issue

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Complete
    • Affects Version/s: 2.0.1
    • Fix Version/s: 2.1 RC2
    • Component/s: Core
    • Environment:
      Replicated in Sun JVM in windows. Happens in Websphere IBM JVM more often.

      Description

      Message handlers in chains are not executed in the order described in the XML. See: more info in the forum entry.

      We think the problem is with the bean name generation for inner beans which sometimes rolls the same id for different beans. Tested only on version 2.0.1.

      Code to replicate is attached.

        Issue Links

          Activity

          Hide
          Oleg Zhurakousky added a comment -

          Someone by the name Jackson Nicholas has sent me an email over the weekend with the identical code so I suspect you are the same person or colleagues.
          Anyway, i've executed the code and here are my findings:

          First, looking at your namespace configuration I am assuming you are using Spring 2.5. SI 2.0 is targeted for Spring 3.0
          Second, when running with 5000 (as in your current version of the test) iterations i got a stack overflow which is understandable giving the implementation details, but do you really expect to have 5000 elements in the chain or even in a single SI config? I ran it with a 1000 elements in the chain and it went fine
          Third you only using one chain and the original issue in the forum was claiming that the process was jumping to another chain, so I am not sure what are we testing here.

          Could you please provide more details? At his point I am not even sure what to look for.

          Show
          Oleg Zhurakousky added a comment - Someone by the name Jackson Nicholas has sent me an email over the weekend with the identical code so I suspect you are the same person or colleagues. Anyway, i've executed the code and here are my findings: First, looking at your namespace configuration I am assuming you are using Spring 2.5. SI 2.0 is targeted for Spring 3.0 Second, when running with 5000 (as in your current version of the test) iterations i got a stack overflow which is understandable giving the implementation details, but do you really expect to have 5000 elements in the chain or even in a single SI config? I ran it with a 1000 elements in the chain and it went fine Third you only using one chain and the original issue in the forum was claiming that the process was jumping to another chain, so I am not sure what are we testing here. Could you please provide more details? At his point I am not even sure what to look for.
          Hide
          Fabian Murariu added a comment -

          ChainParser.parseChild

          After the bean is created it's name is generated via BeanDefinitionReaderUtils.generateBeanName with innerBean==true.

          Inside generateBeanName() for innerBeans the ObjectUtils.getIdentityHexString() is not guaranteed to return a unique number leading to multiple handlers with the same bean id. Once you have handlers with the same id then it's easy to see how messages can end-up in the wrong chains or wrong handlers.

          Show
          Fabian Murariu added a comment - ChainParser.parseChild After the bean is created it's name is generated via BeanDefinitionReaderUtils.generateBeanName with innerBean==true. Inside generateBeanName() for innerBeans the ObjectUtils.getIdentityHexString() is not guaranteed to return a unique number leading to multiple handlers with the same bean id. Once you have handlers with the same id then it's easy to see how messages can end-up in the wrong chains or wrong handlers.
          Hide
          Mark Fisher added a comment - - edited

          We should be able to call generateBeanName(beanDefinition, registry) instead (and that passes FALSE for the inner-bean param value). Technically, these beans are "inner" since they are defined in a chain, but it's clearly a different case than a regular inner bean in a Spring context.

          It might be better still if we generate our own unique names (similar to the way BeanDefinitionReaderUtils does for top-level beans) but we can also PREFIX those bean names with the chain's ID so they do not collide with others.

          Show
          Mark Fisher added a comment - - edited We should be able to call generateBeanName(beanDefinition, registry) instead (and that passes FALSE for the inner-bean param value). Technically, these beans are "inner" since they are defined in a chain, but it's clearly a different case than a regular inner bean in a Spring context. It might be better still if we generate our own unique names (similar to the way BeanDefinitionReaderUtils does for top-level beans) but we can also PREFIX those bean names with the chain's ID so they do not collide with others.
          Hide
          Fabian Murariu added a comment -

          Yes, me and Nick are in the same team, and the test fails reliably with 10000 elements, however you need to run it with -verbose:gc -Xmx256m -Xss8192k.

          Whenever this problem occurs there is a message from spring
          DefaultListableBeanFactory - Overriding bean definition for bean 'org.springframework.integration.config.ServiceActivatorFactoryBean#1e07d3e': replacing [Generic bean: class [org.springframework.integration.config.ServiceActivatorFactoryBean]; scope=prototype; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null] with [Generic bean: class [org.springframework.integration.config.ServiceActivatorFactoryBean];

          Show
          Fabian Murariu added a comment - Yes, me and Nick are in the same team, and the test fails reliably with 10000 elements, however you need to run it with -verbose:gc -Xmx256m -Xss8192k. Whenever this problem occurs there is a message from spring DefaultListableBeanFactory - Overriding bean definition for bean 'org.springframework.integration.config.ServiceActivatorFactoryBean#1e07d3e': replacing [Generic bean: class [org.springframework.integration.config.ServiceActivatorFactoryBean] ; scope=prototype; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null] with [Generic bean: class [org.springframework.integration.config.ServiceActivatorFactoryBean] ;
          Hide
          Oleg Zhurakousky added a comment -

          Which version of Spring you are using and which version of SI?

          Show
          Oleg Zhurakousky added a comment - Which version of Spring you are using and which version of SI?
          Hide
          Oleg Zhurakousky added a comment -

          The reason why I am asking is that I can't seem to reproduce it with the following code which i believe is a simpler version of what you are trying to show:

          Map map = new HashMap();
          for (int i = 0; i < 100000; i++) {
          	BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(ServiceActivatorFactoryBean.class);
          	String name = BeanDefinitionReaderUtils.generateBeanName(builder.getBeanDefinition(), parserContext.getRegistry(), true);
          	if (map.containsKey(name)){
          		throw new RuntimeException("oops");
          	}
          	map.put(name, "bean");	
          }
          
          Show
          Oleg Zhurakousky added a comment - The reason why I am asking is that I can't seem to reproduce it with the following code which i believe is a simpler version of what you are trying to show: Map map = new HashMap(); for ( int i = 0; i < 100000; i++) { BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(ServiceActivatorFactoryBean.class); String name = BeanDefinitionReaderUtils.generateBeanName(builder.getBeanDefinition(), parserContext.getRegistry(), true ); if (map.containsKey(name)){ throw new RuntimeException( "oops" ); } map.put(name, "bean" ); }
          Hide
          Fabian Murariu added a comment -

          We've tested this and it deals with the problem.

          Show
          Fabian Murariu added a comment - We've tested this and it deals with the problem.

            People

            • Assignee:
              Oleg Zhurakousky
              Reporter:
              Fabian Murariu
            • Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: