簡體   English   中英

駱駝JMS處理不起作用

[英]Camel JMS Transacted not working

我正在嘗試使駱駝路由JMS-> HTTP4與Transaction一起工作,但是當發生異常時,消息未傳輸到ActiveMQ.DLQ,我不知道為什么。

下面的示例說明了REST服務的服務器關閉並且路由無法傳遞時可能發生的情況。

我得到正確的異常:

2018-01-18 12:30:50:962-[Camel (LRM-Relay) thread #5 - JmsConsumer[myIncomingQueue]] WARN  o.a.c.s.s.TransactionErrorHandler - Transaction rollback (0x30a1c779) redelivered(false) for (MessageId: ID:MGR-MacBook-Pro.local-51837-1516262355358-4:2:1:1:16 on ExchangeId: ID-MGR-MacBook-Pro-local-1516275047663-0-1) caught: java.net.ConnectException: Cannot connect to CORE REST  

2018-01-18 12:30:50:965-[Camel (LRM-Relay) thread #5 - JmsConsumer[myIncomingQueue]] WARN  o.a.c.c.j.EndpointMessageListener - Execution of JMS message listener failed. Caused by: [org.apache.camel.RuntimeCamelException - java.net.ConnectException: Cannot connect to CORE REST] 
org.apache.camel.RuntimeCamelException: java.net.ConnectException: Cannot connect to CORE REST …

但是消息已被使用並從隊列中刪除。 我的假設是使用事務/事務處理的Camel和AMQ將解決此問題並將消息移至ActiveMQ.DLQ。

我已經讀過《駱駝行動第一版》的第9章。 和谷歌搜索,但沒有找到解決我的問題的任何方法。

我知道我可以創建/定義自己的TransactionErrorHandler()並將消息存儲在我選擇的隊列中,但是我給人的印象是,使用事務處理時這是默認的……

我正在使用獨立的ActiveMQ 5.15.2 Vanilla安裝和配置。
駱駝2.20.1
MacOS 10.13.2上的Java 8_144

我的配置:

@Configuration
 public class Config {
     /**
     * The Camel context.
     */
     final CamelContext camelContext;


     /**
     * The Broker url.
     */
     @Value("${jms.broker.url}")
    private String brokerURL;


    /**
     * Instantiates a new Config.
     *
     * @param camelContext   the sisyfos context
     * @param metricRegistry the metric registry
     */
    @Autowired
    public Config(final CamelContext camelContext, final MetricRegistry metricRegistry) {
        this.camelContext = camelContext;
        this.metricRegistry = metricRegistry;
    }

    @Bean
    public ActiveMQConnectionFactory activeMQConnectionFactory() {
        final ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory();
        activeMQConnectionFactory.setBrokerURL(brokerURL);
        return activeMQConnectionFactory;
    }

    /**
     * Pooled connection factory pooled connection factory.
     *
     * @return the pooled connection factory
     */
    @Bean
    @Primary
    public PooledConnectionFactory pooledConnectionFactory() {
        final PooledConnectionFactory pooledConnectionFactory = new PooledConnectionFactory();
        pooledConnectionFactory.setMaxConnections(8);
        pooledConnectionFactory.setMaximumActiveSessionPerConnection(500);
        pooledConnectionFactory.setConnectionFactory(activeMQConnectionFactory());
        return pooledConnectionFactory;
    }

    /**
     * Jms configuration jms configuration.
     *
     * @return the jms configuration
     */
    @Bean
    public JmsConfiguration jmsConfiguration() {
        final JmsConfiguration jmsConfiguration = new JmsConfiguration();
        jmsConfiguration.setConnectionFactory(pooledConnectionFactory());
        jmsConfiguration.setTransacted(true);
        jmsConfiguration.setTransactionManager(transactionManager());
        jmsConfiguration.setConcurrentConsumers(10);

        return jmsConfiguration;
    }

    /**
     * Transaction manager jms transaction manager.
     *
     * @return the jms transaction manager
     */
    @Bean
    public JmsTransactionManager transactionManager() {
        final JmsTransactionManager transactionManager = new JmsTransactionManager();
        transactionManager.setConnectionFactory(pooledConnectionFactory());
        return transactionManager;
    }

    /**
     * Active mq component active mq component.
     *
     * @return the active mq component
     */
        @Bean
public ActiveMQComponent activeMQComponent(JmsConfiguration jmsConfiguration,
                                           PooledConnectionFactory pooledConnectionFactory,
                                           JmsTransactionManager transactionManager) {
    final ActiveMQComponent activeMQComponent = new ActiveMQComponent();
    activeMQComponent.setConfiguration(jmsConfiguration);
    activeMQComponent.setTransacted(true);
    activeMQComponent.setUsePooledConnection(true);
    activeMQComponent.setConnectionFactory(pooledConnectionFactory);
    activeMQComponent.setTransactionManager(transactionManager);
    return activeMQComponent;
}


}

我的路線:

    @Component
public class SendToCore extends SpringRouteBuilder {

    @Override
    public void configure() throws Exception {
        Logger.getLogger(SendToCore.class).info("Sending to CORE");


        //No retries if first fails due to connection error
        interceptSendToEndpoint("http4:*")
                .choice()
                .when(header("JMSRedelivered").isEqualTo("false"))
                .throwException(new ConnectException("Cannot connect to CORE REST"))
                .end();

        from("activemq:queue:myIncomingQueue")
                .transacted()
                .setHeader(Exchange.CONTENT_TYPE, constant("application/xml"))
                .to("http4:localhost/myRESTservice")
                .log("${header.CamelHttpResponseCode}")
                .end();
    }
}

您可能在某些bean中發現了多余的聲明,這就是我試圖解決的問題……

將鏈接添加到我的Github存儲庫,並帶有一個小測試項目,說明了這一點:
https://github.com/hakuseki/transacted

這可能是SpringBoot自動配置的問題。

如果消息丟失而不是丟失到DLQ,則Camel的ActiveMQ組件會自動提交消息,而不是等待工作完成。

更新:使示例與Java Config配合使用的步驟

注意:我的配置沒有事務管理器,因為您的情況不需要它。 相反,只需在ActiveMQComponent lazyCreateTransactionManager transacted設置為true並將lazyCreateTransactionManagerfalse 然后,您與經紀人進行了“本地”交易,這就是您所需要的。

  • 我從您的路線中刪除了.transacted() (需要事務管理器,但不需要“ JMS本地交易”路線)
  • 我在路由類中注釋了您的錯誤處理程序(需要事務管理器,您可以使用默認的錯誤處理程序)
  • MainApplication禁用JMS和ActiveMQ的自動配置: @SpringBootApplication(exclude = { JmsAutoConfiguration.class, ActiveMQAutoConfiguration.class})
  • 將Java配置替換為以下配置(適應此問題: ConnectionFactory在camel之前銷毀

Java配置:

@Value("${jms.broker.url}") 
String brokerURL;

@Bean
public ActiveMQConnectionFactory connectionFactory() {
    final ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory();
    activeMQConnectionFactory.setBrokerURL(brokerURL);
    return activeMQConnectionFactory;
}

@Bean
@Primary
public PooledConnectionFactory pooledConnectionFactory(ConnectionFactory cf) {
    final PooledConnectionFactory pooledConnectionFactory = new PooledConnectionFactory();
    pooledConnectionFactory.setMaxConnections(1);
    pooledConnectionFactory.setConnectionFactory(cf);
    return pooledConnectionFactory;
}

@Bean(name = "activemq")
@ConditionalOnClass(ActiveMQComponent.class)
public ActiveMQComponent activeMQComponent(ConnectionFactory connectionFactory) {
    ActiveMQComponent activeMQComponent = new ActiveMQComponent();
    activeMQComponent.setConnectionFactory(connectionFactory);
    activeMQComponent.setTransacted(true);
    activeMQComponent.setLazyCreateTransactionManager(false);
    return activeMQComponent;
}

最后,只是為了“運行”路線,我添加了一個小的Camel Route測試

@RunWith(CamelSpringBootRunner.class)
@SpringBootTest(classes = MainApplication.class)
public class SampleCamelApplicationTest {

    @Produce(uri = "activemq:queue:myIncomingQueue")
    protected ProducerTemplate template;

    @Test
    public void shouldProduceMessages() throws Exception {
        template.sendBody("test");
        Thread.sleep(20000); //wait for ActiveMQ redeliveries
    }

}

如果我運行此測試,則消息將發送到ActiveMQ.DLQ

希望這可以幫助

剛剛注意到,如果您希望Spring Boot處理這些池和配置的生命周期,則不應直接調用其方法,而應在方法簽名中將它們作為參數提供

例如這個

public ActiveMQComponent activeMQComponent() {

應該

 public ActiveMQComponent activeMQComponent(JmsConfiguration config, ConnectionFactory cf, ...) {

然后,Spring Boot將為您提供這些bean。

關於您的交易為何不起作用的原因,那么您可以查看《駱駝行動》第二版書籍中的一些交易示例: https : //github.com/camelinaction/camelinaction2/tree/master/chapter12

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM