【问题标题】:Spring integration message loss scenarioSpring集成消息丢失场景
【发布时间】:2018-11-15 16:30:08
【问题描述】:

摘要 - 系统关闭应用程序期间消息丢失。

我有一个用 Spring 集成编写的应用程序,我正在使用“jms:message-driven-channel-adapter”处理来自外部系统的请求。这是通道适配器的配置 -

<jms:message-driven-channel-adapter id="InboundAdapter" destination="InQueue"
                                        connection-factory="connectionFactory"
                                        channel="responseChannel"
                                        error-channel="errorChannel"
                                        acknowledge="transacted"
                                        receive-timeout="50000"
                                        auto-startup="true"/>

我的回复频道是这样的 -

 <int:chain id="processorChain" input-channel="responseChannel">
        <int:service-activator method="doProcess" ref="inputProcessor" />

        <int:router id="inputRouter" method="route">
            <int:mapping value="REQUIRED" channel="builderChannel"/>
            <int:mapping value="NOT_REQUIRED" channel="TerminateChannel"/>
            <bean id="Router" class="xxx.xxx.Router">
            </bean>
        </int:router>
    </int:chain>

现在当我执行“kill -9 pid”时,我看到消息回滚到队列中,一切都很好。但是当我执行'kill pid'时,消息会丢失在某个地方。我已启用 jms 日志,并且可以看到 JMS 侦听器正在等待传输中的消息完成,然后关闭 JMS 使用者,但我仍然没有将消息回滚到我的队列。这是我在日志中看到的日志sn-p

trace: 15.11.18 15:42:46.619 [Thread-10] DEBUG org.springframework.jms.listener.DefaultMessageListenerContainer - 等待消息监听调用者关闭 跟踪:15.11.18 15:42:46.619 [Thread-10] 调试 org.springframework.jms.listener.DefaultMessageListenerContainer - 仍在等待关闭 1 个消息侦听器调用程序(迭代 0)

在此日志之后,它正在调用响应通道中定义的服务激活器。

有人可以解释一下上述行为吗,我期待当我们发出 kill 命令时,所有正在传输的消息都应该回滚到队列中,而不是这样,它试图调用定义的激活器在通道中,在调用最后一个组件是路由器之后,它就完成了。

关于这个主题的任何帮助都会非常有帮助!


在进行了更多调试并用系统敲打我的脑袋后,我发现了它发生的确切场景。让我来看看它是否有意义。当触发系统关闭时,JMS 在停止应用程序之前等待传输中的消息完成,直到此时一切都很好。目前这条链正在执行中 -

<int:chain input-channel="inputchain">
    <int:transformer id="xxx" method="transform">
        <bean class="xxx" />
    </int:transformer>

    <int:service-activator  id="xxx" method="doProcess">
        <bean class="xx">
            <constructor-arg ref="xxx"/>
        </bean>
    </int:service-activator>

    <int:service-activator id="xxx" ref="rulesProcessor" method="doProcess"/>
    <int:service-activator id="xxx" ref="xxx" method="doProcess"/>

    <!-- Existing Flow Continues -->
    <int:router id="xxxRequiredRouter" method="xxxRequired">
        <int:mapping value="Required" channel="firstChannel"/>
        <int:mapping value="NotRequired" channel="secondChannel"/>
        <bean id="xxxRouter" class="xxx.Router" />
        </bean>
    </int:router>

</int:chain>

<int:chain input-channel="secondChannel">

   some logic

</int:chain>

所以线程完成了这个链并优雅地退出。它不会将我的下一条链称为“secondChannel”。我的事务边界没有在这个链“输入链”上完成,它在 secondChannel 的末尾完成。所以我没有将这个事务提交给数据库,因为事务边界位于下一个链的末尾,所以这在 DB 中不可用,并且应用程序认为链执行已经完成所以它是完整的,所以它没有回滚到队列也是。所以最后我的数据库中没有这条消息,它不在队列中。

那么是不是只有在触发关闭时正在执行的链才会完成,并且不会将处理委托给后续链?

【问题讨论】:

  • 为什么要说“消息丢失”,如果你最后解释说一切顺利,直到路由器?当我们调用停止时,我会说这是完全正常的行为,但让飞行中的任务完成。
  • 嗨,Artem,我称之为消息丢失,因为在调用路由器之后,它应该已经进入下一个链(builderChannel)。但是在路由器执行之后,没有其他任何事情发生。由于执行没有完成,所以我的事务没有提交到数据库,并且由于消息没有返回队列,所以当服务器再次返回时我无法处理它。如此有效地我丢失了消息,我将不得不要求源系统再次手动播放它,这是不可接受的解决方案。
  • 如果您的所有进程都在同一个线程中,那么我建议使用JmsTransactionManager 来表示&lt;jms:message-driven-channel-adapter&gt;。此外,由于您提到了基于数据,因此将两个事务管理器包装到ChainedTransactionManager 中可能会更好。请参阅此处了解更多信息:javaworld.com/article/2077963/open-source-tools/…

标签: spring spring-integration message loss


【解决方案1】:

SIGTERM kill 将等待线程完成其工作。

最终容器会中断它,但这只有在它执行可中断的操作时才有用。

【讨论】:

  • 是的,这是期望它应该完成正在进行的任务,如果它没有提交,那么消息应该回滚到队列中。但我没有看到任何这种情况发生,我的事务未完成,因此未提交,消息未返回队列。要么
  • 这是不可能的,除非线程卡在一些不可中断的代码中并且永远不会返回容器并且JVM永远不会关闭。
  • 感谢加里的回复。我知道这很奇怪,它应该按照我们预期的方式工作,但不知何故我没有得到想要的结果。我在想我是否应该使用客户确认而不是使用交易。你认为这对我有帮助吗,因为控件将在客户端代码中,而不是依赖于框架。您认为这是一个好方法吗?
  • 应该没有必要;如果您可以在某处发布一个重现该行为的小项目,我会看看它。
  • 经过更多的调试和系统测试后,我发现了它发生的确切场景。我已经用调查结果更新了实际问题。
猜你喜欢
  • 2013-02-27
  • 1970-01-01
  • 2015-03-28
  • 1970-01-01
  • 2016-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-07
相关资源
最近更新 更多