Spring集成轮询器触发时间间隔错误

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的相关

代码:

我在尝试使用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>