【问题标题】:How to prevent message redelivery from MQ Broker after camel internal redeliveries are successfully processed (transacted camel route)骆驼内部重新传递成功处理后如何防止来自MQ Broker的消息重新传递(事务骆驼路由)
【发布时间】:2019-08-31 21:42:50
【问题描述】:

我正在尝试使用 JPATransactionManager 运行 camel transacted() 路由(独立的 java 进程)是 spring PlatformTransactionManager(因为我希望骆驼路由在单个 DB 事务中运行)但我无法禁止从 MQ 重新传递即使我在 onException 子句中使用了handled(true) 以及我的自定义重新交付策略(已成功执行),但如果事务方法失败的代理。我只希望 MQ 在服务崩溃时重新交付。

下面试过了,还是不行:

  • 在 JMSComponent 配置中设置 setTransacted(false) 以防止骆驼 jms 运行是 transacted_session jms 模式,但它不起作用
  • doTry 和 doCatch 来自事务块的异常
  • 骆驼重新交付,然后是handled(true)。

    onException(Exception.class)
        .log("ERROR OCCURRED")
        .redeliveryPolicyRef("myRedeliveryPolicy")
        .handled(true)
        .to(getPostExceptionRoute());
    
    @Bean
    @Autowired
    public RedeliveryPolicy myRedeliveryPolicy() {
        RedeliveryPolicy myRedeliveryPolicy= new RedeliveryPolicy();
        myRedeliveryPolicy.setMaximumRedeliveries(2);
        myRedeliveryPolicy.setMaximumRedeliveryDelay(2000);
        return myRedeliveryPolicy;
    }
    
    @Bean
    @Autowired
    public JmsComponent jms(IJMSConnectionFactory cf) throws JMSException {
        JmsComponent jmsComponent = new JmsComponent();
        jmsComponent.setConfiguration(jmsConfig(cf));
        jmsComponent.setTransacted(false);
        return jmsComponent;
    }
    
    from("jms:queue:TestQueue?acknowledgementModeName=CLIENT_ACKNOWLEDGE")
        .unmarshal().json(JsonLibrary.Jackson, TestObject.class)
        .transacted()
        .processRef("myPersistInDBProcessor")
    
  • 我希望骆驼按照重新交付政策(有效)尝试重新交付,但 MQ 不应该重新交付。

  • 我希望我的骆驼路线在单个数据库事务中运行。
  • 我希望 MQ 代理仅在我的 java 服务在处理过程中崩溃时重新传递,这样我就不会丢失消息。

【问题讨论】:

    标签: java apache-camel spring-transactions camel-jms


    【解决方案1】:

    我希望骆驼按照重新交付政策(有效)尝试重新交付,但 MQ 不应该重新交付

    当 MQ 绝不能重新交付时(因为您在 Camel 中处理错误),您应该删除 acknowledgementModeName=CLIENT_ACKNOWLEDGE 或显式设置 AUTO_ACKNOWLEDGE(默认值)。

    只要消息未被确认,从代理的角度来看,它就没有被传递。 AUTO_ACKNOWLEDGE 在消费后立即确认消息,如果您从不想要重新交付,这很有意义。

    另一方面,CLIENT_ACKNOWLEDGE 只在特定条件下确认消息,请参阅this post for some more info about this

    由于对新信息发表评论而进行编辑

    如果您想要 MQ 重新传递,但在大多数情况下使用 Camel“覆盖”它们,您必须使用已交易的消息

    通过像这样配置您的 JMS 组件来使用 本地 JMS 代理事务

    jmsComponent.setLazyCreateTransactionManager(false);
    jmsComponent.setTransacted(true);
    

    对于这种类型的事务,您根本不需要 Spring TransactionManager。所以我猜JPATransactionManagerJMS 忽略 并且您的 JMS 消耗应该是事务性的。

    现在,当您的 Camel 错误处理程序使用 handled(true)“吞下”异常时,必须没有 MQ 重新传递。但是当异常传播回代理时,MQ 会重新传递。

    我希望我的骆驼路线在单个数据库事务中运行

    我没有在您的问题中找到任何关于不工作的数据库事务的内容。似乎只有一个处理器可以处理数据库内容。如果这不能正常工作,请在您的问题或单独的问题中描述问题。

    【讨论】:

    • 我只希望 MQ 在 java 服务崩溃的情况下重新交付,而我无法使用 AUTO_ACKNOWLEDGE 模式实现。单数据库事务部分工作正常。
    【解决方案2】:

    根据Apache Karaf Transaction Guide,doTry 和 doCatch 应该按预期工作。您的问题可能是触发错误场景的异常。只有 checked exceptions(没有 RuntimeException 或其后代)不会将正在进行的事务标记为回滚。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-10-19
      • 1970-01-01
      • 1970-01-01
      • 2015-07-24
      • 1970-01-01
      • 2018-08-15
      • 1970-01-01
      相关资源
      最近更新 更多