Spring集成轮询器触发时间间隔错误
代码: 我在尝试使用Spring集成创建jdbc轮询器时遇到问题 当我向表中输入新数据时,处理速度比预期的慢:除了每隔60秒触发一次轮询之外,一切正常,我不明白为什么 2015-05-2710:50:40234调试表达式评估QLParameterSourceFactory-解析表达式#根。![pk]至(pk列表) 2015-05-2710:51:40234调试表达式评估QLParameterSourceFactory-解析表达式#根。![pk]至(pk列表) 这是spring集成配置xml的相关部分:Spring集成轮询器触发时间间隔错误,spring,jdbc,spring-integration,poller,Spring,Jdbc,Spring Integration,Poller,代码: 我在尝试使用Spring集成创建jdbc轮询器时遇到问题 当我向表中输入新数据时,处理速度比预期的慢:除了每隔60秒触发一次轮询之外,一切正常,我不明白为什么 2015-05-2710:50:40234调试表达式评估QLParameterSourceFactory-解析表达式#根。![pk]至(pk列表) 2015-05-2710:51:40234调试表达式评估QLParameterSourceFactory-解析表达式#根。![pk]至(pk列表) 这是spring集成配置xml的相关
<task:executor id="pollerPool" pool-size="5-20" queue-capacity="0" rejection-policy="CALLER_RUNS" keep-alive="5"/>
<!--<task:executor id="processingPool" pool-size="5-20" queue-capacity="0" rejection-policy="CALLER_RUNS" keep-alive="5"/> -->
<bean id="jdbcSource" class="org.springframework.integration.jdbc.JdbcPollingChannelAdapter">
<constructor-arg ref="dataSource"/>
<constructor-arg value="XXXXXXXXXXXXXX"/>
<property name="updateSql" value="XXXXXXXXXXXXXXXX"/>
<property name="maxRowsPerPoll" value="50"/>
</bean>
<int:inbound-channel-adapter send-timeout="10000" auto-startup="false" id="inboundAdapter" ref="jdbcSource" channel="jdbcOutputChannel">
<int:poller receive-timeout="3000" time-unit="MILLISECONDS" fixed-rate="0" error-channel="errorChannel" task-executor="pollerPool">
<int:advice-chain>
<ref bean="threadPrepareInterceptor"/>
<ref bean="txAdvice"/>
</int:advice-chain>
</int:poller>
</int:inbound-channel-adapter>
<int:service-activator id="serviceActivator" input-channel="jdbcOutputChannel" ref="someServiceActivatorBean"/>
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<int:channel id="jdbcOutputChannel" >
<!-- using direct channel -->
<!--<int:dispatcher task-executor="processingPool"/>-->
</int:channel>
你能帮我理解这个问题吗
更新:
关于事务的“jdbcOutputChannel”建议,我同意,并根据您的提示修改了配置,因为它更干净(无论如何,service activator也在单独的事务中运行,即使xml示例中没有概述)
关于我遇到的问题,我尝试删除所有其他spring集成组件,轮询器会像我预期的那样持续触发(我知道固定速率=0太高了:)
相反,在项目中配置其他轮询器时,我的轮询器似乎也会继承相同的超时:
<int:service-activator id="someOtherServiceActivator">
<int:poller fixed-rate="0" error-channel="someOtherPollerErrorChannel" receive-timeout="60000" />
</int:service-activator>
将其他轮询器的超时时间切换到10000ms,我的轮询器也会每10秒触发一次(而不是60秒)。
我无法共享完整的spring集成配置,但我想问:完全分离的轮询器是否可能修改彼此的行为
更新2:
我创建了一个单独的项目,试图重现这个问题,但仍然无法做到这一点。
因此,我尝试删除以下配置,引入该配置是为了仅在应用程序完全启动并运行时启动轮询器:
<int:publish-subscribe-channel id="startupChannel" />
<int:control-bus input-channel="controlBusChannel" />
<int-event:inbound-channel-adapter channel="startupChannel" event-types="org.springframework.context.event.ContextRefreshedEvent"/>
<int:transformer input-channel="startupChannel" expression="'@inboundAdapter.start()'" output-channel="controlBusChannel" />
<int:transformer input-channel="startupChannel" expression="'@someOtherServiceActivator.start()'" output-channel="controlBusChannel" />
而问题已经消失,即使这样我也能完全理解原因。
无论如何,为我的民意调查者创建一个不同的startupChannel非常有效:
<int:publish-subscribe-channel id="globalStartupChannel" />
<int:publish-subscribe-channel id="myStartupChannel" />
<int:control-bus input-channel="controlBusChannel" />
<int-event:inbound-channel-adapter channel="globalStartupChannel" event-types="org.springframework.context.event.ContextRefreshedEvent"/>
<int-event:inbound-channel-adapter channel="myStartupChannel" event-types="org.springframework.context.event.ContextRefreshedEvent"/>
<int:transformer input-channel="globalStartupChannel" expression="'@someOtherServiceActivator.start()'" output-channel="controlBusChannel" />
<int:transformer input-channel="myStartupChannel" expression="'@inboundAdapter.start()'" output-channel="controlBusChannel" />
更新3:
在为您准备带有代码的项目时,我注意到以下日志:
信息:没有明确定义名为“taskScheduler”的bean。因此,将创建默认的ThreadPoolTaskScheduler。
因此,我添加了以下配置,现在一切正常:
<task:scheduler id="taskScheduler" pool-size="20" />
我猜默认的池大小是10,因此在使用totalNumberOfPollers>taskScheduler.size()时,配置会以某种方式被覆盖。
我说得对吗
谢谢
朱利奥我无法再现你的处境;我建议您在两次轮询之间进行线程转储,以查看线程正在做什么 也就是说,0的固定利率是非常激进的;您的DBA可能会毫不延迟地抛出一个合适的轮询 另外,
jdbcOutputChannel
,作为一个ExecutorChannel
,意味着事务将在消息发送到该通道后立即提交。如果希望流在事务中运行,则不应在此处使用调度程序
编辑:
我还是无法用这个重现你的处境
<int:control-bus input-channel="input"/>
<int-event:inbound-channel-adapter channel="ps" event-types="org.springframework.context.event.ContextRefreshedEvent"/>
<int:publish-subscribe-channel id="ps" />
<int:transformer input-channel="ps" output-channel="input" expression="'@foo.start()'" />
<int:transformer input-channel="ps" output-channel="input" expression="'@sa.start()'" />
<int:inbound-channel-adapter id="foo" channel="bar" expression="'foo'" auto-startup="false">
<int:poller fixed-rate="1000" />
</int:inbound-channel-adapter>
<int:channel id="bar">
<int:queue />
</int:channel>
<int:service-activator id="sa" input-channel="bar" output-channel="baz" auto-startup="false"
expression="payload.toUpperCase()">
<int:poller fixed-rate="6000" receive-timeout="0" />
</int:service-activator>
<int:logging-channel-adapter id="baz" level="ERROR"/>
通过此配置,调度程序资源(线程)在QueueChannel
s中被阻塞,并且正如您所发现的,您已经耗尽了所有资源
一种解决方案是增加调度程序池中的线程数
通过这种配置,您似乎正试图通过让轮询器在queue receive()方法中不断等待来获得轮询器的按需零延迟消息传递
如果你负担不起任何延迟,请考虑使用<代码>直接通道< /代码> s。如果不希望下游端点在调用方的线程上运行,请使用
ExecutorChannel
s
<task:executor id="exec" pool-size="100"/>
<int:channel id="otherMessageChannel1">
<int:dispatcher task-executor="exec" />
</int:channel>
这通常比您当前的设置更受欢迎。非常感谢您的快速回答,我编辑了我的原始问题并进行了进一步分析。很有趣;另一个轮询器不应该影响jdbc轮询器——如果影响了,那就是一个bug;现在,看着代码,我看不出它是如何做到的;我得进行一些测试(但可能是明天)。您能确认您使用的是哪个版本的Spring Integration吗?再次感谢:)我使用的版本是2.1.0.Release,这是从2012年1月开始的一个非常旧的版本(从软件的角度来说是古老的)(尽管我仍然不记得我们必须修复轮询器交互的问题)。这个,很奇怪;即使回到2.1.0.0版本,我仍然无法重现您的问题。使用单独的事件适配器和通道在逻辑上与为同一事件使用发布/子通道相同。比较显示事件和控制总线消息的两个启动日志(调试时)会很有趣。我会用我的测试配置更新答案。你能更清楚地解释一下你所说的“…创建一个不同的startupChannel…”是什么意思吗?我在问题中提供了一个例子。啊-是的;我想你有很多“阻止”民意调查者。通常,入站通道适配器轮询器不会阻塞—当没有数据时,源返回null,线程被释放用于其他用途。默认情况下,QueueChannel轮询器将在队列中阻塞1秒,等待消息;只有这样,线程才会被释放。在一个应用程序中有这么多异步(QueueChannel)切换是非常罕见的;这可能表明对何时使用它们存在一些误解。OTOH,如果你真的需要那么多,你可以减少轮询器上的接收超时,或者使用更多的调度程序线程。也就是说,虽然你会遇到线程饥饿,但不清楚为什么饥饿会持续60秒,
<task:executor id="exec" pool-size="100"/>
<int:channel id="otherMessageChannel1">
<int:dispatcher task-executor="exec" />
</int:channel>