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