private SimpleMessageListenerContainer verifyContainer(AbstractEndpoint endpoint) { SimpleMessageListenerContainer container; Advice retry; container = TestUtils.getPropertyValue( endpoint, "messageListenerContainer", SimpleMessageListenerContainer.class); assertEquals(AcknowledgeMode.NONE, container.getAcknowledgeMode()); assertThat(container.getQueueNames()[0], startsWith("foo.props.0")); assertFalse(TestUtils.getPropertyValue(container, "transactional", Boolean.class)); assertEquals(2, TestUtils.getPropertyValue(container, "concurrentConsumers")); assertEquals(3, TestUtils.getPropertyValue(container, "maxConcurrentConsumers")); assertFalse(TestUtils.getPropertyValue(container, "defaultRequeueRejected", Boolean.class)); assertEquals(20, TestUtils.getPropertyValue(container, "prefetchCount")); assertEquals(10, TestUtils.getPropertyValue(container, "txSize")); retry = TestUtils.getPropertyValue(container, "adviceChain", Advice[].class)[0]; assertEquals(23, TestUtils.getPropertyValue(retry, "retryOperations.retryPolicy.maxAttempts")); assertEquals( 2000L, TestUtils.getPropertyValue(retry, "retryOperations.backOffPolicy.initialInterval")); assertEquals( 20000L, TestUtils.getPropertyValue(retry, "retryOperations.backOffPolicy.maxInterval")); assertEquals( 5.0, TestUtils.getPropertyValue(retry, "retryOperations.backOffPolicy.multiplier")); List<?> requestMatchers = TestUtils.getPropertyValue( endpoint, "headerMapper.requestHeaderMatcher.strategies", List.class); assertEquals(1, requestMatchers.size()); assertEquals( "foo", TestUtils.getPropertyValue(requestMatchers.get(0), "patterns", Collection.class) .iterator() .next()); return container; }
@Test public void testParseWithTx() throws Exception { SimpleMessageListenerContainer container = beanFactory.getBean("container6", SimpleMessageListenerContainer.class); assertTrue(container.isChannelTransacted()); assertEquals(5, ReflectionTestUtils.getField(container, "txSize")); }
private HeartBeatListener() { setAlive(false); RabbitAdmin rabbitAdmin = RabbitConfiguration.getRabbitAdmin(); Queue queue = rabbitAdmin.declareQueue(); FanoutExchange exchange = new FanoutExchange(HEART_BEAT_EXCHANGE); rabbitAdmin.declareBinding(BindingBuilder.bind(queue).to(exchange)); HeartBeatMessageListener heartBeatMessageListener = new HeartBeatMessageListener(); SimpleMessageListenerContainer messageListenerContainer = new SimpleMessageListenerContainer(); messageListenerContainer.setQueues(queue); messageListenerContainer.setConnectionFactory(RabbitConfiguration.getConnectionFactory()); messageListenerContainer.setMessageListener(heartBeatMessageListener); messageListenerContainer.start(); Thread thread = new Thread( new Runnable() { @Override public void run() { while (true) { try { Message result; result = heartBeats.poll(TIMEOUT, TimeUnit.MILLISECONDS); if (result == null) { setAlive(false); } else { setAlive(true); } } catch (InterruptedException e) { setAlive(false); } } } }, "server-heart-beat-listener"); thread.start(); }
@Test public void testParseWithDefaultQueueRejectedFalse() throws Exception { SimpleMessageListenerContainer container = beanFactory.getBean("container5", SimpleMessageListenerContainer.class); assertEquals(1, ReflectionTestUtils.getField(container, "concurrentConsumers")); assertEquals(false, ReflectionTestUtils.getField(container, "defaultRequeueRejected")); assertFalse(container.isChannelTransacted()); }
@Test public void testParseWithQueues() throws Exception { SimpleMessageListenerContainer container = beanFactory.getBean("container2", SimpleMessageListenerContainer.class); Queue queue = beanFactory.getBean("bar", Queue.class); assertEquals( "[foo, " + queue.getName() + "]", Arrays.asList(container.getQueueNames()).toString()); assertTrue(TestUtils.getPropertyValue(container, "missingQueuesFatal", Boolean.class)); assertFalse(TestUtils.getPropertyValue(container, "autoDeclare", Boolean.class)); }
@Bean SimpleMessageListenerContainer container( ConnectionFactory connectionFactory, MessageListenerAdapter listenerAdapter) { SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(); container.setConnectionFactory(connectionFactory); container.setQueueNames(MAIL_MESSAGE_CMD_QUEUE); container.setMessageListener(listenerAdapter); return container; }
@Bean public SimpleMessageListenerContainer messageListenerContainer(AmqpAdmin amqpAdmin) { SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(); container.setConnectionFactory(rabbitConnectionFactory()); container.setQueueNames(clientQueue(amqpAdmin).getName()); container.setMessageListener( new MessageListenerAdapter(serviceMessageReceiver, messageConverter)); // No acks will be sent (incompatible with channelTransacted=true). RabbitMQ calls this // "autoack" because the broker assumes all messages are acked without any action from the // consumer. container.setAcknowledgeMode(AcknowledgeMode.NONE); return container; }
private SimpleMessageListenerContainer createContainer(Object listener) { SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(template.getConnectionFactory()); container.setMessageListener(new MessageListenerAdapter(listener)); container.setQueueNames(queue.getName()); container.setTxSize(txSize); container.setPrefetchCount(txSize); container.setConcurrentConsumers(concurrentConsumers); container.setChannelTransacted(transactional); container.setAcknowledgeMode(AcknowledgeMode.AUTO); container.afterPropertiesSet(); container.start(); return container; }
private void doListenerWithExceptionTest(CountDownLatch latch, Object listener) throws Exception { container = createContainer(listener); if (acknowledgeMode.isTransactionAllowed()) { // Should only need one message if it is going to fail for (int i = 0; i < concurrentConsumers; i++) { template.convertAndSend(queue.getName(), i + "foo"); } } else { for (int i = 0; i < messageCount; i++) { template.convertAndSend(queue.getName(), i + "foo"); } } try { boolean waited = latch.await(10 + Math.max(1, messageCount / 10), TimeUnit.SECONDS); assertTrue("Timed out waiting for message", waited); } finally { // Wait for broker communication to finish before trying to stop // container Thread.sleep(300L); container.shutdown(); Thread.sleep(300L); } if (acknowledgeMode.isTransactionAllowed()) { assertNotNull(template.receiveAndConvert(queue.getName())); } else { assertNull(template.receiveAndConvert(queue.getName())); } }
private void doTest(int concurrentConsumers, ContainerConfigurer configurer) { int messageCount = 10; RabbitTemplate template = new RabbitTemplate(); CachingConnectionFactory connectionFactory = new CachingConnectionFactory(); connectionFactory.setHost("localhost"); connectionFactory.setChannelCacheSize(concurrentConsumers); connectionFactory.setPort(BrokerTestUtils.getPort()); template.setConnectionFactory(connectionFactory); SimpleMessageConverter messageConverter = new SimpleMessageConverter(); messageConverter.setCreateMessageIds(true); template.setMessageConverter(messageConverter); for (int i = 0; i < messageCount; i++) { template.convertAndSend(queue1.getName(), new Integer(i)); template.convertAndSend(queue2.getName(), new Integer(i)); } final SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory); final CountDownLatch latch = new CountDownLatch(messageCount * 2); PojoListener listener = new PojoListener(latch); container.setMessageListener(new MessageListenerAdapter(listener)); container.setAcknowledgeMode(AcknowledgeMode.AUTO); container.setChannelTransacted(true); container.setConcurrentConsumers(concurrentConsumers); configurer.configure(container); container.afterPropertiesSet(); container.start(); try { int timeout = Math.min(1 + messageCount / concurrentConsumers, 30); boolean waited = latch.await(timeout, TimeUnit.SECONDS); logger.info("All messages recovered: " + waited); assertEquals(concurrentConsumers, container.getActiveConsumerCount()); assertTrue("Timed out waiting for messages", waited); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new IllegalStateException("unexpected interruption"); } finally { container.shutdown(); assertEquals(0, container.getActiveConsumerCount()); } assertNull(template.receiveAndConvert(queue1.getName())); assertNull(template.receiveAndConvert(queue2.getName())); connectionFactory.destroy(); }
@After public void clear() throws Exception { // Wait for broker communication to finish before trying to stop container Thread.sleep(300L); logger.debug("Shutting down at end of test"); if (container != null) { container.shutdown(); } ((DisposableBean) template.getConnectionFactory()).destroy(); }
@Test public void testPublisherConfirmWithSendAndReceive() throws Exception { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference<CorrelationData> confirmCD = new AtomicReference<CorrelationData>(); templateWithConfirmsEnabled.setConfirmCallback( new ConfirmCallback() { @Override public void confirm(CorrelationData correlationData, boolean ack, String cause) { confirmCD.set(correlationData); latch.countDown(); } }); SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(this.connectionFactoryWithConfirmsEnabled); container.setQueueNames(ROUTE); container.setMessageListener( new MessageListenerAdapter( new Object() { @SuppressWarnings("unused") public String handleMessage(String in) { return in.toUpperCase(); } })); container.start(); CorrelationData correlationData = new CorrelationData("abc"); String result = (String) this.templateWithConfirmsEnabled.convertSendAndReceive( ROUTE, (Object) "message", correlationData); container.stop(); assertEquals("MESSAGE", result); assertTrue(latch.await(10, TimeUnit.SECONDS)); assertEquals(correlationData, confirmCD.get()); }
@Test public void testListenerSunnyDay() throws Exception { CountDownLatch latch = new CountDownLatch(messageCount); for (int i = 0; i < messageCount; i++) { template.convertAndSend(queue.getName(), i + "foo"); } SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(template.getConnectionFactory()); container.setMessageListener(new MessageListenerAdapter(new PojoListener(latch))); container.setChannelTransacted(transactional); container.setConcurrentConsumers(concurrentConsumers); container.setQueueName(queue.getName()); container.afterPropertiesSet(); container.start(); try { boolean waited = latch.await(50, TimeUnit.MILLISECONDS); assertFalse("Expected time out waiting for message", waited); container.stop(); Thread.sleep(500L); container.start(); if (transactional) { waited = latch.await(5, TimeUnit.SECONDS); assertTrue("Timed out waiting for message", waited); } else { waited = latch.await(500, TimeUnit.MILLISECONDS); // If non-transactional we half expect to lose messages assertFalse("Expected time out waiting for message", waited); } } finally { // Wait for broker communication to finish before trying to stop // container Thread.sleep(300L); container.shutdown(); } assertNull(template.receiveAndConvert(queue.getName())); }
@Test public void testParseWithQueueNames() throws Exception { SimpleMessageListenerContainer container = beanFactory.getBean("container1", SimpleMessageListenerContainer.class); assertEquals(AcknowledgeMode.MANUAL, container.getAcknowledgeMode()); assertEquals(beanFactory.getBean(ConnectionFactory.class), container.getConnectionFactory()); assertEquals(MessageListenerAdapter.class, container.getMessageListener().getClass()); DirectFieldAccessor listenerAccessor = new DirectFieldAccessor(container.getMessageListener()); assertEquals( beanFactory.getBean(TestBean.class), listenerAccessor.getPropertyValue("delegate")); assertEquals("handle", listenerAccessor.getPropertyValue("defaultListenerMethod")); Queue queue = beanFactory.getBean("bar", Queue.class); assertEquals( "[foo, " + queue.getName() + "]", Arrays.asList(container.getQueueNames()).toString()); assertEquals(5, ReflectionTestUtils.getField(container, "concurrentConsumers")); assertEquals(6, ReflectionTestUtils.getField(container, "maxConcurrentConsumers")); assertEquals(1234L, ReflectionTestUtils.getField(container, "startConsumerMinInterval")); assertEquals(2345L, ReflectionTestUtils.getField(container, "stopConsumerMinInterval")); assertEquals(12, ReflectionTestUtils.getField(container, "consecutiveActiveTrigger")); assertEquals(34, ReflectionTestUtils.getField(container, "consecutiveIdleTrigger")); assertEquals(9876L, ReflectionTestUtils.getField(container, "receiveTimeout")); Map<?, ?> consumerArgs = TestUtils.getPropertyValue(container, "consumerArgs", Map.class); assertEquals(1, consumerArgs.size()); Object xPriority = consumerArgs.get("x-priority"); assertNotNull(xPriority); assertEquals(10, xPriority); assertEquals( Long.valueOf(5555), TestUtils.getPropertyValue(container, "recoveryBackOff.interval", Long.class)); assertFalse(TestUtils.getPropertyValue(container, "exclusive", Boolean.class)); assertFalse(TestUtils.getPropertyValue(container, "missingQueuesFatal", Boolean.class)); assertTrue(TestUtils.getPropertyValue(container, "autoDeclare", Boolean.class)); assertEquals(5, TestUtils.getPropertyValue(container, "declarationRetries")); assertEquals(1000L, TestUtils.getPropertyValue(container, "failedDeclarationRetryInterval")); assertEquals(30000L, TestUtils.getPropertyValue(container, "retryDeclarationInterval")); assertEquals( beanFactory.getBean("tagger"), TestUtils.getPropertyValue(container, "consumerTagStrategy")); Collection<?> group = beanFactory.getBean("containerGroup", Collection.class); assertEquals(3, group.size()); assertThat( group, Matchers.contains( beanFactory.getBean("container1"), beanFactory.getBean("testListener1"), beanFactory.getBean("testListener2"))); assertEquals(1235L, ReflectionTestUtils.getField(container, "idleEventInterval")); assertEquals("container1", container.getListenerId()); }
@Test public void testParseWithQueueNames() throws Exception { SimpleMessageListenerContainer container = this.context.getBean("testListener", SimpleMessageListenerContainer.class); assertEquals(AcknowledgeMode.MANUAL, container.getAcknowledgeMode()); assertEquals(this.context.getBean(ConnectionFactory.class), container.getConnectionFactory()); assertEquals(MessageListenerAdapter.class, container.getMessageListener().getClass()); DirectFieldAccessor listenerAccessor = new DirectFieldAccessor(container.getMessageListener()); assertEquals( this.context.getBean(TestBean.class), listenerAccessor.getPropertyValue("delegate")); assertEquals("handle", listenerAccessor.getPropertyValue("defaultListenerMethod")); Queue queue = this.context.getBean("bar", Queue.class); assertEquals( "[foo, " + queue.getName() + "]", Arrays.asList(container.getQueueNames()).toString()); }
@Override protected void executeListener(Channel channel, Message message) throws Throwable { super.executeListener(channel, message); channel.basicAck(message.getMessageProperties().getDeliveryTag(), false); if (log.isDebugEnabled()) log.debug("Acknowledging message: " + new String(message.getBody())); }
private SimpleMessageListenerContainer createContainer(Object listener) { SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(template.getConnectionFactory()); container.setMessageListener(listener); container.setQueueNames(queue.getName()); container.setTxSize(txSize); container.setPrefetchCount(txSize); container.setConcurrentConsumers(concurrentConsumers); container.setChannelTransacted(transactional); container.setAcknowledgeMode(acknowledgeMode); // requires RabbitMQ 3.2.x // container.setConsumerArguments(Collections. <String, Object> singletonMap("x-priority", // Integer.valueOf(10))); if (externalTransaction) { container.setTransactionManager(new TestTransactionManager()); } container.afterPropertiesSet(); container.start(); return container; }
public void invokeListener(Channel channel, Message message) throws Exception { SimpleMessageListenerContainer.super.invokeListener(channel, message); }
private void doRegisterConsumer( String name, MessageChannel moduleInputChannel, Queue queue, RabbitPropertiesAccessor properties, boolean isPubSub) { // Fix for XD-2503 // Temporarily overrides the thread context classloader with the one where the // SimpleMessageListenerContainer // is defined // This allows for the proxying that happens while initializing the // SimpleMessageListenerContainer to work // correctly ClassLoader originalClassloader = Thread.currentThread().getContextClassLoader(); try { ClassUtils.overrideThreadContextClassLoader( SimpleMessageListenerContainer.class.getClassLoader()); SimpleMessageListenerContainer listenerContainer = new SimpleMessageListenerContainer(this.connectionFactory); listenerContainer.setAcknowledgeMode( properties.getAcknowledgeMode(this.defaultAcknowledgeMode)); listenerContainer.setChannelTransacted( properties.getTransacted(this.defaultChannelTransacted)); listenerContainer.setDefaultRequeueRejected( properties.getRequeueRejected(this.defaultDefaultRequeueRejected)); if (!isPubSub) { int concurrency = properties.getConcurrency(this.defaultConcurrency); concurrency = concurrency > 0 ? concurrency : 1; listenerContainer.setConcurrentConsumers(concurrency); int maxConcurrency = properties.getMaxConcurrency(this.defaultMaxConcurrency); if (maxConcurrency > concurrency) { listenerContainer.setMaxConcurrentConsumers(maxConcurrency); } } listenerContainer.setPrefetchCount(properties.getPrefetchCount(this.defaultPrefetchCount)); listenerContainer.setTxSize(properties.getTxSize(this.defaultTxSize)); listenerContainer.setTaskExecutor(new SimpleAsyncTaskExecutor(queue.getName() + "-")); listenerContainer.setQueues(queue); int maxAttempts = properties.getMaxAttempts(this.defaultMaxAttempts); if (maxAttempts > 1 || properties.getRepublishToDLQ(this.defaultRepublishToDLQ)) { RetryOperationsInterceptor retryInterceptor = RetryInterceptorBuilder.stateless() .maxAttempts(maxAttempts) .backOffOptions( properties.getBackOffInitialInterval(this.defaultBackOffInitialInterval), properties.getBackOffMultiplier(this.defaultBackOffMultiplier), properties.getBackOffMaxInterval(this.defaultBackOffMaxInterval)) .recoverer(determineRecoverer(name, properties)) .build(); listenerContainer.setAdviceChain(new Advice[] {retryInterceptor}); } listenerContainer.setAfterReceivePostProcessors(this.decompressingPostProcessor); listenerContainer.setMessagePropertiesConverter( RabbitMessageChannelBinder.inboundMessagePropertiesConverter); listenerContainer.afterPropertiesSet(); AmqpInboundChannelAdapter adapter = new AmqpInboundChannelAdapter(listenerContainer); adapter.setBeanFactory(this.getBeanFactory()); DirectChannel bridgeToModuleChannel = new DirectChannel(); bridgeToModuleChannel.setBeanFactory(this.getBeanFactory()); bridgeToModuleChannel.setBeanName(name + ".bridge"); adapter.setOutputChannel(bridgeToModuleChannel); adapter.setBeanName("inbound." + name); DefaultAmqpHeaderMapper mapper = new DefaultAmqpHeaderMapper(); mapper.setRequestHeaderNames( properties.getRequestHeaderPattens(this.defaultRequestHeaderPatterns)); mapper.setReplyHeaderNames(properties.getReplyHeaderPattens(this.defaultReplyHeaderPatterns)); adapter.setHeaderMapper(mapper); adapter.afterPropertiesSet(); Binding consumerBinding = Binding.forConsumer(name, adapter, moduleInputChannel, properties); addBinding(consumerBinding); ReceivingHandler convertingBridge = new ReceivingHandler(); convertingBridge.setOutputChannel(moduleInputChannel); convertingBridge.setBeanName(name + ".convert.bridge"); convertingBridge.afterPropertiesSet(); bridgeToModuleChannel.subscribe(convertingBridge); consumerBinding.start(); } finally { Thread.currentThread().setContextClassLoader(originalClassloader); } }
/** Verifies that an up-stack RabbitTemplate uses the listener's channel (MessageListener). */ @SuppressWarnings("unchecked") @Test public void testMessageListener() throws Exception { ConnectionFactory mockConnectionFactory = mock(ConnectionFactory.class); Connection mockConnection = mock(Connection.class); final Channel onlyChannel = mock(Channel.class); when(onlyChannel.isOpen()).thenReturn(true); final CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory(mockConnectionFactory); when(mockConnectionFactory.newConnection((ExecutorService) null)).thenReturn(mockConnection); when(mockConnection.isOpen()).thenReturn(true); final AtomicReference<Exception> tooManyChannels = new AtomicReference<Exception>(); doAnswer( new Answer<Channel>() { boolean done; @Override public Channel answer(InvocationOnMock invocation) throws Throwable { if (!done) { done = true; return onlyChannel; } tooManyChannels.set(new Exception("More than one channel requested")); Channel channel = mock(Channel.class); when(channel.isOpen()).thenReturn(true); return channel; } }) .when(mockConnection) .createChannel(); final AtomicReference<Consumer> consumer = new AtomicReference<Consumer>(); doAnswer( new Answer<String>() { @Override public String answer(InvocationOnMock invocation) throws Throwable { consumer.set((Consumer) invocation.getArguments()[6]); return null; } }) .when(onlyChannel) .basicConsume( anyString(), anyBoolean(), anyString(), anyBoolean(), anyBoolean(), anyMap(), any(Consumer.class)); final CountDownLatch commitLatch = new CountDownLatch(1); doAnswer( new Answer<String>() { @Override public String answer(InvocationOnMock invocation) throws Throwable { commitLatch.countDown(); return null; } }) .when(onlyChannel) .txCommit(); final CountDownLatch latch = new CountDownLatch(1); SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(cachingConnectionFactory); container.setMessageListener( new MessageListener() { @Override public void onMessage(Message message) { RabbitTemplate rabbitTemplate = new RabbitTemplate(cachingConnectionFactory); rabbitTemplate.setChannelTransacted(true); // should use same channel as container rabbitTemplate.convertAndSend("foo", "bar", "baz"); latch.countDown(); } }); container.setQueueNames("queue"); container.setChannelTransacted(true); container.setShutdownTimeout(100); container.afterPropertiesSet(); container.start(); consumer .get() .handleDelivery( "qux", new Envelope(1, false, "foo", "bar"), new BasicProperties(), new byte[] {0}); assertTrue(latch.await(10, TimeUnit.SECONDS)); Exception e = tooManyChannels.get(); if (e != null) { throw e; } verify(mockConnection, Mockito.times(1)).createChannel(); assertTrue(commitLatch.await(10, TimeUnit.SECONDS)); verify(onlyChannel).txCommit(); verify(onlyChannel) .basicPublish( Mockito.anyString(), Mockito.anyString(), Mockito.anyBoolean(), Mockito.any(BasicProperties.class), Mockito.any(byte[].class)); // verify close() was never called on the channel DirectFieldAccessor dfa = new DirectFieldAccessor(cachingConnectionFactory); List<?> channels = (List<?>) dfa.getPropertyValue("cachedChannelsTransactional"); assertEquals(0, channels.size()); container.stop(); }
/** * Verifies that the listener channel is not exposed when so configured and up-stack * RabbitTemplate uses the additional channel. created when exposeListenerChannel is false * (ChannelAwareMessageListener). */ @SuppressWarnings("unchecked") @Test public void testChannelAwareMessageListenerDontExpose() throws Exception { ConnectionFactory mockConnectionFactory = mock(ConnectionFactory.class); Connection mockConnection = mock(Connection.class); final Channel firstChannel = mock(Channel.class); when(firstChannel.isOpen()).thenReturn(true); final Channel secondChannel = mock(Channel.class); when(secondChannel.isOpen()).thenReturn(true); final SingleConnectionFactory singleConnectionFactory = new SingleConnectionFactory(mockConnectionFactory); when(mockConnectionFactory.newConnection((ExecutorService) null)).thenReturn(mockConnection); when(mockConnection.isOpen()).thenReturn(true); final AtomicReference<Exception> tooManyChannels = new AtomicReference<Exception>(); doAnswer( new Answer<Channel>() { boolean done; @Override public Channel answer(InvocationOnMock invocation) throws Throwable { if (!done) { done = true; return firstChannel; } return secondChannel; } }) .when(mockConnection) .createChannel(); final AtomicReference<Consumer> consumer = new AtomicReference<Consumer>(); doAnswer( new Answer<String>() { @Override public String answer(InvocationOnMock invocation) throws Throwable { consumer.set((Consumer) invocation.getArguments()[6]); return null; } }) .when(firstChannel) .basicConsume( anyString(), anyBoolean(), anyString(), anyBoolean(), anyBoolean(), anyMap(), any(Consumer.class)); final CountDownLatch commitLatch = new CountDownLatch(1); doAnswer( new Answer<String>() { @Override public String answer(InvocationOnMock invocation) throws Throwable { commitLatch.countDown(); return null; } }) .when(firstChannel) .txCommit(); final CountDownLatch latch = new CountDownLatch(1); final AtomicReference<Channel> exposed = new AtomicReference<Channel>(); SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(singleConnectionFactory); container.setMessageListener( new ChannelAwareMessageListener() { @Override public void onMessage(Message message, Channel channel) { exposed.set(channel); RabbitTemplate rabbitTemplate = new RabbitTemplate(singleConnectionFactory); rabbitTemplate.setChannelTransacted(true); // should use same channel as container rabbitTemplate.convertAndSend("foo", "bar", "baz"); latch.countDown(); } }); container.setQueueNames("queue"); container.setChannelTransacted(true); container.setExposeListenerChannel(false); container.setShutdownTimeout(100); container.afterPropertiesSet(); container.start(); consumer .get() .handleDelivery( "qux", new Envelope(1, false, "foo", "bar"), new BasicProperties(), new byte[] {0}); assertTrue(latch.await(10, TimeUnit.SECONDS)); Exception e = tooManyChannels.get(); if (e != null) { throw e; } // once for listener, once for exposed + 0 for template (used bound) verify(mockConnection, Mockito.times(2)).createChannel(); assertTrue(commitLatch.await(10, TimeUnit.SECONDS)); verify(firstChannel).txCommit(); verify(secondChannel).txCommit(); verify(secondChannel) .basicPublish( Mockito.anyString(), Mockito.anyString(), Mockito.anyBoolean(), Mockito.any(BasicProperties.class), Mockito.any(byte[].class)); assertSame(secondChannel, exposed.get()); verify(firstChannel, Mockito.never()).close(); verify(secondChannel, Mockito.times(1)).close(); container.stop(); }
private SimpleMessageListenerContainer createContainer() throws Exception { // if (!messageDriven) TODO: no container attributes would apply if not message-driven SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(); if (this.acknowledgeMode != null) { container.setAcknowledgeMode(this.acknowledgeMode); } if (!ObjectUtils.isEmpty(this.adviceChain)) { container.setAdviceChain(this.adviceChain); } container.setAutoStartup(this.autoStartup); container.setChannelTransacted(this.channelTransacted); if (this.concurrentConsumers != null) { container.setConcurrentConsumers(this.concurrentConsumers); } container.setConnectionFactory(this.connectionFactory); if (this.errorHandler != null) { container.setErrorHandler(this.errorHandler); } if (this.exposeListenerChannel != null) { container.setExposeListenerChannel(this.exposeListenerChannel); } if (this.messagePropertiesConverter != null) { container.setMessagePropertiesConverter(this.messagePropertiesConverter); } if (this.phase != null) { container.setPhase(this.phase); } if (this.prefetchCount != null) { container.setPrefetchCount(this.prefetchCount); } if (this.receiveTimeout != null) { container.setReceiveTimeout(this.receiveTimeout); } if (this.recoveryInterval != null) { container.setRecoveryInterval(this.recoveryInterval); } if (this.shutdownTimeout != null) { container.setShutdownTimeout(this.shutdownTimeout); } if (this.taskExecutor != null) { container.setTaskExecutor(this.taskExecutor); } if (this.transactionAttribute != null) { container.setTransactionAttribute(this.transactionAttribute); } if (this.transactionManager != null) { container.setTransactionManager(this.transactionManager); } if (this.txSize != null) { container.setTxSize(this.txSize); } if (this.missingQueuesFatal != null) { container.setMissingQueuesFatal(this.missingQueuesFatal); } return container; }
@Test public void testConsumerProperties() throws Exception { MessageBus bus = getMessageBus(); Properties properties = new Properties(); properties.put( "transacted", "true"); // test transacted with defaults; not allowed with ackmode NONE bus.bindConsumer("props.0", new DirectChannel(), properties); @SuppressWarnings("unchecked") List<Binding> bindings = TestUtils.getPropertyValue(bus, "messageBus.bindings", List.class); assertEquals(1, bindings.size()); AbstractEndpoint endpoint = bindings.get(0).getEndpoint(); SimpleMessageListenerContainer container = TestUtils.getPropertyValue( endpoint, "messageListenerContainer", SimpleMessageListenerContainer.class); assertEquals(AcknowledgeMode.AUTO, container.getAcknowledgeMode()); assertEquals("xdbus.props.0", container.getQueueNames()[0]); assertTrue(TestUtils.getPropertyValue(container, "transactional", Boolean.class)); assertEquals(1, TestUtils.getPropertyValue(container, "concurrentConsumers")); assertNull(TestUtils.getPropertyValue(container, "maxConcurrentConsumers")); assertTrue(TestUtils.getPropertyValue(container, "defaultRequeueRejected", Boolean.class)); assertEquals(1, TestUtils.getPropertyValue(container, "prefetchCount")); assertEquals(1, TestUtils.getPropertyValue(container, "txSize")); Advice retry = TestUtils.getPropertyValue(container, "adviceChain", Advice[].class)[0]; assertEquals(3, TestUtils.getPropertyValue(retry, "retryOperations.retryPolicy.maxAttempts")); assertEquals( 1000L, TestUtils.getPropertyValue(retry, "retryOperations.backOffPolicy.initialInterval")); assertEquals( 10000L, TestUtils.getPropertyValue(retry, "retryOperations.backOffPolicy.maxInterval")); assertEquals( 2.0, TestUtils.getPropertyValue(retry, "retryOperations.backOffPolicy.multiplier")); bus.unbindConsumers("props.0"); assertEquals(0, bindings.size()); properties = new Properties(); properties.put("ackMode", "NONE"); properties.put("backOffInitialInterval", "2000"); properties.put("backOffMaxInterval", "20000"); properties.put("backOffMultiplier", "5.0"); properties.put("concurrency", "2"); properties.put("maxAttempts", "23"); properties.put("maxConcurrency", "3"); properties.put("prefix", "foo."); properties.put("prefetch", "20"); properties.put("requestHeaderPatterns", "foo"); properties.put("requeue", "false"); properties.put("txSize", "10"); properties.put("partitionIndex", 0); bus.bindConsumer("props.0", new DirectChannel(), properties); @SuppressWarnings("unchecked") List<Binding> bindingsNow = TestUtils.getPropertyValue(bus, "messageBus.bindings", List.class); assertEquals(1, bindingsNow.size()); endpoint = bindingsNow.get(0).getEndpoint(); container = verifyContainer(endpoint); assertEquals("foo.props.0", container.getQueueNames()[0]); try { bus.bindPubSubConsumer("dummy", null, properties); fail("Expected exception"); } catch (IllegalArgumentException e) { assertThat( e.getMessage(), allOf( containsString("RabbitMessageBus does not support consumer properties: "), containsString("partitionIndex"), containsString("concurrency"), containsString(" for dummy."))); } try { bus.bindConsumer("queue:dummy", null, properties); fail("Expected exception"); } catch (IllegalArgumentException e) { assertEquals( "RabbitMessageBus does not support consumer property: partitionIndex for queue:dummy.", e.getMessage()); } bus.unbindConsumers("props.0"); assertEquals(0, bindingsNow.size()); }
@Override protected void invokeListener(Channel channel, Message message) throws Exception { super.invokeListener(channel, message); // channel.basicAck(message.getMessageProperties().getDeliveryTag(), false); }
private void doTestRetry( int messageCount, int txSize, int failFrequency, int concurrentConsumers, boolean stateful) throws Exception { int failedMessageCount = messageCount / failFrequency + (messageCount % failFrequency == 0 ? 0 : 1); RabbitTemplate template = createTemplate(concurrentConsumers); for (int i = 0; i < messageCount; i++) { template.convertAndSend(queue.getName(), i); } final SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(template.getConnectionFactory()); PojoListener listener = new PojoListener(failFrequency); container.setMessageListener(new MessageListenerAdapter(listener)); container.setAcknowledgeMode(AcknowledgeMode.AUTO); container.setChannelTransacted(true); container.setTxSize(txSize); container.setConcurrentConsumers(concurrentConsumers); final CountDownLatch latch = new CountDownLatch(failedMessageCount); container.setAdviceChain(new Advice[] {createRetryInterceptor(latch, stateful)}); container.setQueueNames(queue.getName()); container.afterPropertiesSet(); container.start(); try { int timeout = Math.min(1 + 2 * messageCount / concurrentConsumers, 30); final int count = messageCount; logger.debug("Waiting for messages with timeout = " + timeout + " (s)"); Executors.newSingleThreadExecutor() .execute( () -> { while (container.getActiveConsumerCount() > 0) { try { Thread.sleep(100L); } catch (InterruptedException e) { latch.countDown(); Thread.currentThread().interrupt(); return; } } for (int i = 0; i < count; i++) { latch.countDown(); } }); boolean waited = latch.await(timeout, TimeUnit.SECONDS); logger.info("All messages recovered: " + waited); assertEquals(concurrentConsumers, container.getActiveConsumerCount()); assertTrue("Timed out waiting for messages", waited); // Retried each failure 3 times (default retry policy)... assertEquals(3 * failedMessageCount, listener.getCount()); // All failed messages recovered assertEquals(null, template.receiveAndConvert(queue.getName())); } finally { container.shutdown(); ((DisposableBean) template.getConnectionFactory()).destroy(); assertEquals(0, container.getActiveConsumerCount()); } }