我过期的JMS消息在哪里?

时间:2013-05-17 15:25:01

标签: activemq apache-camel

我正在使用ActiveMQ 5.8.0和Camel 2.10.4。我正在从JMS队列中读取ExchangePattern.InOnly消息,并希望将在给定时间内未处理的消息明确地过期到命名的死信队列。

我有以下路线:

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();
        }
    }
}

第二条消息根本没有到期,尽管考虑到@ Petter的提示(谢谢)。

我有这个单元测试模式在测试中的其他地方工作,它明确地从Camel中的事务中抛出异常,但我宁愿不必自己手动开始查看标题,而这一切似乎已经处理完了。 / p>

1 个答案:

答案 0 :(得分:9)

在队列中过期一次或在ActiveMQ中命中队列的消息将采取以下任一操作:

  1. 如果消息是持久的,那么它将被放置在队列ActiveMQ.DLQ上。
  2. 如果邮件是非持久性的,则会立即将其丢弃而不另行通知。
  3. 在您的ActiveMQ配置中,您已禁用持久性,因此快速猜测您的消息将在视线中删除,而不会通知您的应用程序。

    了解更多here