PDA

View Full Version : Dispatcher has no subscribers under CI-725, Spring 3.0



greenwayb
Dec 17th, 2009, 08:33 PM
I have a scenario where I use on Server 1 (S1) a jms:outbound-channel-adaptor to send messgaes to S2.

When S1 starts, which is deployed as a war inside an ear, it first performs a database query to see if there is any data that requires recovering.

Under spring-integration 2 M1, with approrpiate spring 3 this worked correctly (after I ensured recovery was part of an InitializingBean rather than trigggered
via a start operation).

Yesterday i upgrade spring and therefore to a nightly build of spring integration (725) for compatibility.

However now when the container starts, and recovery records are found, the message is pushed out but a "Dispatcher has no subscribers message" is encountered.




Caused by: org.springframework.integration.message.MessageDel iveryException: failed to send Message to channel 'dispatchXdmDataItemInputChannel'
at org.springframework.integration.channel.AbstractMe ssageChannel.send(AbstractMessageChannel.java:188)
at org.springframework.integration.channel.AbstractMe ssageChannel.send(AbstractMessageChannel.java:153)
at org.springframework.integration.channel.MessageCha nnelTemplate.doSend(MessageChannelTemplate.java:22 4)
at org.springframework.integration.channel.MessageCha nnelTemplate.send(MessageChannelTemplate.java:181)
at org.springframework.integration.gateway.AbstractMe ssagingGateway.send(AbstractMessagingGateway.java: 126)
at org.springframework.integration.gateway.GatewayPro xyFactoryBean.invokeGatewayMethod(GatewayProxyFact oryBean.java:210)
at org.springframework.integration.gateway.GatewayPro xyFactoryBean.invoke(GatewayProxyFactoryBean.java: 176)
at org.springframework.aop.framework.ReflectiveMethod Invocation.proceed(ReflectiveMethodInvocation.java :172)
at org.springframework.aop.framework.JdkDynamicAopPro xy.invoke(JdkDynamicAopProxy.java:202)
at $Proxy43.dispatch(Unknown Source)
at com.jdv.xdm.xdma.Dispatcher.dispatch(Dispatcher.ja va:177)
at com.jdv.xdm.xdma.Dispatcher.start(Dispatcher.java: 110)
at com.jdv.xdm.xdma.Dispatcher.afterPropertiesSet(Dis patcher.java:130)
at org.springframework.beans.factory.support.Abstract AutowireCapableBeanFactory$5.run(AbstractAutowireC apableBeanFactory.java:1451)
at java.security.AccessController.doPrivileged(Native Method)
at org.springframework.beans.factory.support.Abstract AutowireCapableBeanFactory.invokeInitMethods(Abstr actAutowireCapableBeanFactory.java:1449)
at org.springframework.beans.factory.support.Abstract AutowireCapableBeanFactory.initializeBean(Abstract AutowireCapableBeanFactory.java:1398)
... 148 more
Caused by: java.lang.IllegalStateException: Dispatcher has no subscribers.
at org.springframework.integration.dispatcher.Unicast ingDispatcher.doDispatch(UnicastingDispatcher.java :97)
at org.springframework.integration.dispatcher.Unicast ingDispatcher.dispatch(UnicastingDispatcher.java:9 0)
at org.springframework.integration.channel.AbstractSu bscribableChannel.doSend(AbstractSubscribableChann el.java:43)
at org.springframework.integration.channel.AbstractMe ssageChannel.send(AbstractMessageChannel.java:180)



If this exception occurs then the container fails to start.

If instead i disable recovery mode (ie dont recover on initialisation) but instead trigger it manually from JMX it will work. Therefore i know my bean
configuration is correct and its more of a lifecycle issue.

Any ideas?

Some config thats in use:



<beans:bean id="dispatcherCORE" class="com.jdv.xdm.xdma.Dispatcher" destroy-method="stop" depends-on="dispatcherGateway">
<beans:property name="QOwner" value="CORE" />
<beans:property name="dao" ref="xdmDao" />
<beans:property name="iddao" ref="idDao" />
<beans:property name="dispatcherGateway" ref="dispatcherGateway" />

<beans:property name="messageContainer">
<beans:bean class="org.springframework.jms.listener.DefaultMessageLis tenerContainer">
<beans:property name="connectionFactory">
<beans:bean class="org.springframework.jms.connection.SingleConnectio nFactory">
<beans:property name="targetConnectionFactory" ref="connectionFactory"/>
</beans:bean>
</beans:property>
<beans:property name="destination" ref="xdmCoreSourceQueue"/>
<beans:property name="messageListener" ref="dispatcherCORE" />
<beans:property name="autoStartup" value="false" />
</beans:bean>
</beans:property>
<beans:property name="startWithRecoveryMode" value="true" />
</beans:bean>



<integration:gateway id="dispatcherGateway" service-interface="com.jdv.xdm.xdma.DispatcherGateway" />
<integration:channel id="dispatchXdmDataItemInputChannel" />
<jms:outbound-channel-adapter destination="xdmSendQueue"
channel="dispatchXdmDataItemInputChannel"
/>

<integration:channel id="dispatchXdmDataItemJmsInputChannel" />

greenwayb
Dec 17th, 2009, 09:19 PM
From the debugger, when triggered manaully after startup (through jmx) handler is there, see this screenshot:

http://i.imgur.com/fdqIg.png

When the call is made as part of the InitializingBean the handlers size is 0 and hence the error.

greenwayb
Dec 17th, 2009, 09:56 PM
I also tried a couple of different things, @Autowired to inject the dispatcherGateway and also inside the Dispatcher class used an explicit applicationContext.getBean call, but the same issue still occurred.

iwein
Dec 20th, 2009, 04:37 AM
Apparently in the latest version the subscription happens later than before, and that causes your error. You should make sure your component is initialized only after SI is fully loaded.

For this particular type of use case you can use LifeCycle or ApplicationContextEvents. Those allow you to intercept state changes after the initialization.

The fact that it worked before is luck, not a feature. You could get the result you want with depends-on hacks, but that will likely couple your config to a specific version of the framework.

Hope this helps.

Mark Fisher
Dec 20th, 2009, 04:21 PM
The Spring Integration components now implement the new (as of Spring 3.0) SmartLifecycle interface which enables "phases" for lifecycle execution. Any component implementing that interface will be started in ascending order (as indicated by the phase value) and stopped in descending order.

The endpoints that are connected to "subscribable" channels (where dispatchers are involved) now start in the earliest possible phase. However, those same components used to start upon initialization. The old *more eager* behavior was necessary when there was no support for ordered lifecycle processing. Now that SmartLifecycle does enable that, we are able to treat lifecycle consistently while relying on the order (subscribers register before pollers start).

If possible, you could implement SmartLifecycle and set a phase value that is greater than Integer.MIN_VALUE.

Let me know if that explanation is clear and/or if you have any more questions.

greenwayb
Dec 20th, 2009, 05:45 PM
Thanks will give it a try, however due to Christmas period won't be able to try it until beginning of January. Will post the results when i do.

Thanks for the assistance.