Activemq 我的过期JMS消息在哪里?

Activemq 我的过期JMS消息在哪里?,activemq,apache-camel,Activemq,Apache Camel,我正在使用ActiveMQ 5.8.0和Camel 2.10.4。我正在读取来自JMS队列的ExchangePattern.inoOnly消息,并希望将那些在给定时间内未被处理的消息显式地终止到命名死信队列 我有以下路线: public class FulfillmentRequestRoute extends RouteBuilder { @Override public void configure() throws Exception { errorHa

我正在使用ActiveMQ 5.8.0和Camel 2.10.4。我正在读取来自JMS队列的ExchangePattern.inoOnly消息,并希望将那些在给定时间内未被处理的消息显式地终止到命名死信队列

我有以下路线:

public class FulfillmentRequestRoute extends RouteBuilder {

    @Override
    public void configure() throws Exception {

        errorHandler(deadLetterChannel("jms:queue:dead").useOriginalMessage());
        from("jms:queue:fulfillmentRequest?explicitQosEnabled=true&timeToLive=10000&transacted=true")
            .transacted()
            .to("mock:initialProcessor");
    }
}
以及以下ActiveMQ配置:

<!-- Configure the ActiveMQ JMS broker server to listen on TCP port 61610 -->
<broker:broker useJmx="true" persistent="true" brokerName="myBroker">
    <broker:transportConnectors>
        <!-- expose a VM transport for in-JVM transport between AMQ and Camel on the server side -->
        <broker:transportConnector name="vm" uri="vm://myBroker" />
        <!-- expose a TCP transport for clients to use -->
        <broker:transportConnector name="tcp" uri="tcp://localhost:${tcp.port}" />
    </broker:transportConnectors>
    <broker:persistenceAdapter>
        <broker:kahaPersistenceAdapter directory="target/olp-activemq-data" maxDataFileLength="33554432"/>
    </broker:persistenceAdapter>
    <broker:destinationPolicy>
        <broker:policyMap>
          <broker:policyEntries>
            <!-- Set the following policy on all queues using the '>' wildcard -->
            <broker:policyEntry queue=">">
              <broker:deadLetterStrategy>
                <broker:sharedDeadLetterStrategy processExpired="true"
                                                 processNonPersistent="true" />
              </broker:deadLetterStrategy>
            </broker:policyEntry>
          </broker:policyEntries>
        </broker:policyMap>
    </broker:destinationPolicy>
</broker:broker>

<!-- Configure Camel ActiveMQ to use the embedded ActiveMQ broker declared above -->
<!-- Using the ActiveMQComponent gives us connection pooling for free -->
<bean id="jms" class="org.apache.activemq.camel.component.ActiveMQComponent">
    <property name="brokerURL" value="vm://myBroker" />
    <property name="transacted" value="true"/>
    <property name="transactionManager" ref="jmsTransactionManager"/>
    <property name="acceptMessagesWhileStopping" value="false"/>
</bean>
<bean id="jmsTransactionManager" class="org.springframework.jms.connection.JmsTransactionManager">
    <property name="connectionFactory" ref="jmsConnectionFactory"/>
</bean>
<bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
    <property name="brokerURL" value="vm://myBroker" />
</bean>

最后,我有一个单元测试,它创建了两条消息,一条将被处理,另一条将超时

@RunWith(CamelSpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:/META-INF/spring/camel-server.xml"})
public class FulfillmentRequestTimeoutTest {

    @EndpointInject(uri = "mock:initialProcessor")
    protected MockEndpoint mockEndpoint;

    @Produce
    protected ProducerTemplate template;

    protected ConsumerTemplate consumer;

    @Autowired
    @Qualifier("camel-server")
    protected CamelContext context;

    @DirtiesContext
    @Test
    public void requestPutOnTimedOutQueueIfOlderThanTimeToLive() throws Exception {

        // Given
        consumer = context.createConsumerTemplate();

        int expectedValidMessageCount = 2;
        mockEndpoint.expectedMessageCount(expectedValidMessageCount);        

        // When 
        String xmlBody1 = "<?xml version=\"1.0\"?><body>THIS WILL NOT TIMEOUT</body>";
        template.sendBody("jms:queue:fulfillmentRequest", ExchangePattern.InOnly, xmlBody1);

        long ttl = System.currentTimeMillis() - 12000000;
        String xmlBody2 = "<?xml version=\"1.0\"?><body>!!!!!TIMED OUT!!!!!</body>";
        template.sendBodyAndHeader("jms:queue:fulfillmentRequest", ExchangePattern.InOnly, xmlBody2, "JMSExpiration", ttl);

        // Then
        // The second message is not processed
        mockEndpoint.assertIsSatisfied();                         // This should not pass with "2" set above

        List<Exchange> list = mockEndpoint.getReceivedExchanges();
        String notTimedOutMessageBody = (String) list.get(0).getIn().getBody(String.class);

        assertEquals(xmlBody1, notTimedOutMessageBody);

        Thread.sleep(5000);

        // And is instead routed to the timedOut JMS queue
        Object dlqBody  = consumer.receiveBodyNoWait("jms:queue:dead");
        assertNotNull("Should not lose the message", dlqBody);          // This fails
        assertEquals(xmlBody2, dlqBody);
    }

    @Configuration
    public static class ContextConfig extends SingleRouteCamelConfiguration {

        @Bean
        public RouteBuilder route() {
            return new FulfillmentRequestRoute();
        }
    }
}
@RunWith(CamelSpringJUnit4ClassRunner.class)
@ContextConfiguration(位置={“classpath:/META-INF/spring/camel server.xml”})
公共类FulfillmentRequestTimeoutTest{
@端点注入(uri=“mock:initialProcessor”)
受保护的MockEndpoint MockEndpoint;
@产生
受保护的产品模板;
受保护的消费者模板消费者;
@自动连线
@限定符(“骆驼服务器”)
受保护的上下文;
@肮脏的环境
@试验
public void requestPutOnTimedOutQueueIfOlderThanTimeToLive()引发异常{
//给定
consumer=context.createConsumerTemplate();
int expectedValidMessageCount=2;
mockEndpoint.expectedMessageCount(expectedValidMessageCount);
//什么时候
String xmlBody1=“这不会超时”;
sendBody(“jms:queue:fulfillmentRequest”、ExchangePattern.inoOnly、xmlBody1);
long ttl=System.currentTimeMillis()-12000000;
字符串xmlBody2=“!!!!!超时!!!”;
sendboyandheader(“jms:queue:fulfillmentRequest”,ExchangePattern.inoOnly,xmlBody2,“JMSExpiration”,ttl);
//然后
//第二条消息未被处理
mockEndpoint.Assertessatified();//这不应与上面的“2”一起传递
List=mockEndpoint.getReceivedExchanges();
String notTimedOutMessageBody=(String)list.get(0.getIn().getBody(String.class);
assertEquals(xmlBody1,notTimedOutMessageBody);
睡眠(5000);
//而是路由到timedOut JMS队列
对象dlqBody=consumer.receiveBodyNoWait(“jms:queue:dead”);
assertNotNull(“不应丢失消息”,dlqBody);//此操作失败
assertEquals(xmlBody2,dlqBody);
}
@配置
公共静态类ContextConfig扩展了SingleRouteCamelConfiguration{
@豆子
公共路由生成器路由(){
返回新的FulfillmentRequestRoute();
}
}
}
第二条消息根本没有过期,尽管考虑了下面@Petter的提示(谢谢)


我在其他测试中使用了这个单元测试模式,这些测试显式地从Camel中的事务抛出异常,但我不希望在这一切似乎都已得到处理的情况下,自己手动开始查找标头。

一旦队列中的消息过期,或者当ActiveMQ中的消息命中队列时,这些消息将执行以下操作之一:

  • 如果消息是持久的,那么它将被放置在队列
    ActiveMQ.DLQ
  • 如果该消息是非持久性的,则将立即丢弃该消息,无需另行通知
  • 在ActiveMQ配置中,您已经禁用了持久性,因此可以快速猜测,您的消息将在不通知应用程序的情况下被删除


    阅读更多内容

    看来我并没有像我想象的那样让信息过期。如果我将expectedMessageCount设置为=2,那么我会看到这两条消息都被处理到mockEndpoint。(不是我认为expectedMessageCount应该做的…)至少这是我在DLQ上看不到第二条消息的一个原因。我将尝试像@Petter建议的那样打开持久性,看看会发生什么……仍然破碎。我将开始浏览activemq调试日志,看看会出现什么。。。