[英]What is the difference between a transactional client and transacted=true when using a JMS route in apache camel?
[英]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組件會自動提交消息,而不是等待工作完成。
注意:我的配置沒有事務管理器,因為您的情況不需要它。 相反,只需在
ActiveMQComponent
lazyCreateTransactionManager
transacted
設置為true
並將lazyCreateTransactionManager
為false
。 然后,您與經紀人進行了“本地”交易,這就是您所需要的。
.transacted()
(需要事務管理器,但不需要“ JMS本地交易”路線) MainApplication
禁用JMS和ActiveMQ的自動配置: @SpringBootApplication(exclude = { JmsAutoConfiguration.class, ActiveMQAutoConfiguration.class})
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.