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 Queue generateQueue(String name) { CachingConnectionFactory connectionFactory = new CachingConnectionFactory(); RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory); Queue queue = new Queue(name); queue.setAdminsThatShouldDeclare(rabbitAdmin); return queue; }
private void doSunnyDayTest(CountDownLatch latch, Object listener) throws Exception { container = createContainer(listener); for (int i = 0; i < messageCount; i++) { template.convertAndSend(queue.getName(), i + "foo"); } boolean waited = latch.await(Math.max(10, messageCount / 20), TimeUnit.SECONDS); assertTrue("Timed out waiting for message", waited); assertNull(template.receiveAndConvert(queue.getName())); }
public void configureRabbitListeners(RabbitListenerEndpointRegistrar registrar) { Queue queue = rabbitAdmin.declareQueue(); rabbitAdmin.declareBinding( new Binding(queue.getName(), Binding.DestinationType.QUEUE, "crudEvents", "#", null)); SimpleRabbitListenerEndpoint endpoint = new SimpleRabbitListenerEndpoint(); endpoint.setId("testMessageListener"); endpoint.setQueueNames(queue.getName()); endpoint.setMessageListener(testMessageListener(null)); registrar.registerEndpoint(endpoint); }
@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)); }
@Test public void testListenerTransactionalSunnyDay() throws Exception { transactional = true; CountDownLatch latch = new CountDownLatch(messageCount); container = createContainer(new TestListener(latch, false)); for (int i = 0; i < messageCount; i++) { template.convertAndSend(queue.getName(), i + "foo"); } int timeout = Math.min(1 + messageCount / (4 * concurrentConsumers), 30); logger.debug("Waiting for messages with timeout = " + timeout + " (s)"); boolean waited = latch.await(timeout, TimeUnit.SECONDS); assertTrue("Timed out waiting for message", waited); 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()); }
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(); }
@Test public void testArgumentsQueue() throws Exception { Queue queue = beanFactory.getBean("arguments", Queue.class); assertNotNull(queue); RabbitTemplate template = new RabbitTemplate(new CachingConnectionFactory(BrokerTestUtils.getPort())); RabbitAdmin rabbitAdmin = new RabbitAdmin(template.getConnectionFactory()); rabbitAdmin.deleteQueue(queue.getName()); rabbitAdmin.declareQueue(queue); assertEquals(100L, queue.getArguments().get("x-message-ttl")); template.convertAndSend(queue.getName(), "message"); Thread.sleep(200); String result = (String) template.receiveAndConvert(queue.getName()); assertEquals(null, result); }
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; }
@Override public void bindPubSubConsumer( String name, MessageChannel moduleInputChannel, Properties properties) { String exchangeName = BinderUtils.removeGroupFromPubSub(name); if (logger.isInfoEnabled()) { logger.info("declaring pubsub for inbound: " + name + ", bound to: " + exchangeName); } RabbitPropertiesAccessor accessor = new RabbitPropertiesAccessor(properties); validateConsumerProperties(name, properties, SUPPORTED_PUBSUB_CONSUMER_PROPERTIES); String prefix = accessor.getPrefix(this.defaultPrefix); FanoutExchange exchange = new FanoutExchange(applyPrefix(prefix, applyPubSub(exchangeName))); declareExchangeIfNotPresent(exchange); Queue queue; boolean durable = accessor.isDurable(this.defaultDurableSubscription); String queueName = applyPrefix(prefix, name); if (durable) { Map<String, Object> args = queueArgs(accessor, queueName); queue = new Queue(queueName, true, false, false, args); } else { queue = new Queue(queueName, false, false, true); } declareQueueIfNotPresent(queue); org.springframework.amqp.core.Binding binding = BindingBuilder.bind(queue).to(exchange); this.rabbitAdmin.declareBinding(binding); // register with context so they will be redeclared after a connection failure if (!this.autoDeclareContext.containsBean(applyPubSub(name))) { this.autoDeclareContext.getBeanFactory().registerSingleton(applyPubSub(name), queue); } String bindingBeanName = exchange.getName() + "." + queue.getName() + ".binding"; if (!this.autoDeclareContext.containsBean(bindingBeanName)) { this.autoDeclareContext.getBeanFactory().registerSingleton(bindingBeanName, binding); } doRegisterConsumer(name, moduleInputChannel, queue, accessor, true); if (durable) { autoBindDLQ(name, accessor); } }
@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())); }
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 testMultipleQueueNamesWithConcurrentConsumers() { doTest(3, container -> container.setQueueNames(queue1.getName(), queue2.getName())); }
@Test public void testMultipleQueueNames() { doTest(1, container -> container.setQueueNames(queue1.getName(), queue2.getName())); }
/** * @author Mark Fisher * @author Gunnar Hillert * @author Gary Russell */ public class MessageListenerContainerMultipleQueueIntegrationTests { private static Log logger = LogFactory.getLog(MessageListenerContainerMultipleQueueIntegrationTests.class); private static Queue queue1 = new Queue("test.queue.1"); private static Queue queue2 = new Queue("test.queue.2"); @Rule public BrokerRunning brokerIsRunning = BrokerRunning.isRunningWithEmptyQueues(queue1.getName(), queue2.getName()); @Rule public LogLevelAdjuster logLevels = new LogLevelAdjuster( Level.INFO, RabbitTemplate.class, SimpleMessageListenerContainer.class, BlockingQueueConsumer.class); @Rule public ExpectedException exception = ExpectedException.none(); @After public void tearDown() { this.brokerIsRunning.removeTestQueues(); } @Test public void testMultipleQueues() { doTest(1, container -> container.setQueues(queue1, queue2)); } @Test public void testMultipleQueueNames() { doTest(1, container -> container.setQueueNames(queue1.getName(), queue2.getName())); } @Test public void testMultipleQueuesWithConcurrentConsumers() { doTest(3, container -> container.setQueues(queue1, queue2)); } @Test public void testMultipleQueueNamesWithConcurrentConsumers() { doTest(3, container -> container.setQueueNames(queue1.getName(), queue2.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(); } @FunctionalInterface private interface ContainerConfigurer { void configure(SimpleMessageListenerContainer container); } @SuppressWarnings("unused") private static class PojoListener { private final AtomicInteger count = new AtomicInteger(); private final CountDownLatch latch; PojoListener(CountDownLatch latch) { this.latch = latch; } public void handleMessage(int value) throws Exception { logger.debug(value + ":" + count.getAndIncrement()); latch.countDown(); } public int getCount() { return count.get(); } } }
/** * @author Dave Syer * @author Gary Russell * @author Gunnar Hillert * @author Artem Bilan * @since 1.0 */ public class MessageListenerContainerRetryIntegrationTests { private static Log logger = LogFactory.getLog(MessageListenerContainerRetryIntegrationTests.class); private static Queue queue = new Queue("test.queue"); @Rule public BrokerRunning brokerIsRunning = BrokerRunning.isRunningWithEmptyQueues(queue.getName()); @Rule public LogLevelAdjuster logLevels = new LogLevelAdjuster( Level.ERROR, RabbitTemplate.class, SimpleMessageListenerContainer.class, BlockingQueueConsumer.class); @Rule public LogLevelAdjuster traceLevels = new LogLevelAdjuster( Level.ERROR, StatefulRetryOperationsInterceptorFactoryBean.class, MessageListenerContainerRetryIntegrationTests.class); @Rule public ExpectedException exception = ExpectedException.none(); @Rule public RepeatProcessor repeats = new RepeatProcessor(); private RetryTemplate retryTemplate; private MessageConverter messageConverter; private RabbitTemplate createTemplate(int concurrentConsumers) { RabbitTemplate template = new RabbitTemplate(); CachingConnectionFactory connectionFactory = new CachingConnectionFactory(); connectionFactory.setHost("localhost"); connectionFactory.setChannelCacheSize(concurrentConsumers); connectionFactory.setPort(BrokerTestUtils.getPort()); template.setConnectionFactory(connectionFactory); if (messageConverter == null) { SimpleMessageConverter messageConverter = new SimpleMessageConverter(); messageConverter.setCreateMessageIds(true); this.messageConverter = messageConverter; } template.setMessageConverter(messageConverter); return template; } @After public void tearDown() { if (this.repeats.isFinalizing()) { this.brokerIsRunning.removeTestQueues(); } } @Test public void testStatefulRetryWithAllMessagesFailing() throws Exception { int messageCount = 10; int txSize = 1; int failFrequency = 1; int concurrentConsumers = 3; doTestStatefulRetry(messageCount, txSize, failFrequency, concurrentConsumers); } @Test public void testStatelessRetryWithAllMessagesFailing() throws Exception { int messageCount = 10; int txSize = 1; int failFrequency = 1; int concurrentConsumers = 3; doTestStatelessRetry(messageCount, txSize, failFrequency, concurrentConsumers); } @Test public void testStatefulRetryWithNoMessageIds() throws Exception { int messageCount = 2; int txSize = 1; int failFrequency = 1; int concurrentConsumers = 1; SimpleMessageConverter messageConverter = new SimpleMessageConverter(); // There will be no key for these messages so they cannot be recovered... messageConverter.setCreateMessageIds(false); this.messageConverter = messageConverter; // Beware of context cache busting if retry policy fails... this.retryTemplate = new RetryTemplate(); this.retryTemplate.setRetryContextCache(new MapRetryContextCache(1)); // The container should have shutdown, so there are now no active consumers exception.expectMessage("expected:<1> but was:<0>"); doTestStatefulRetry(messageCount, txSize, failFrequency, concurrentConsumers); } @Test @Repeat(10) public void testStatefulRetryWithTxSizeAndIntermittentFailure() throws Exception { int messageCount = 10; int txSize = 4; int failFrequency = 3; int concurrentConsumers = 3; doTestStatefulRetry(messageCount, txSize, failFrequency, concurrentConsumers); } @Test public void testStatefulRetryWithMoreMessages() throws Exception { int messageCount = 200; int txSize = 10; int failFrequency = 6; int concurrentConsumers = 3; doTestStatefulRetry(messageCount, txSize, failFrequency, concurrentConsumers); } private Advice createRetryInterceptor(final CountDownLatch latch, boolean stateful) throws Exception { AbstractRetryOperationsInterceptorFactoryBean factory; if (stateful) { factory = new StatefulRetryOperationsInterceptorFactoryBean(); } else { factory = new StatelessRetryOperationsInterceptorFactoryBean(); } factory.setMessageRecoverer( (message, cause) -> { logger.warn( "Recovered: [" + SerializationUtils.deserialize(message.getBody()).toString() + "], message: " + message); latch.countDown(); }); if (retryTemplate == null) { retryTemplate = new RetryTemplate(); } factory.setRetryOperations(retryTemplate); return factory.getObject(); } private void doTestStatefulRetry( int messageCount, int txSize, int failFrequency, int concurrentConsumers) throws Exception { doTestRetry(messageCount, txSize, failFrequency, concurrentConsumers, true); } private void doTestStatelessRetry( int messageCount, int txSize, int failFrequency, int concurrentConsumers) throws Exception { doTestRetry(messageCount, txSize, failFrequency, concurrentConsumers, 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()); } } private static class PojoListener { private final AtomicInteger count = new AtomicInteger(); private final int failFrequency; PojoListener(int failFrequency) { this.failFrequency = failFrequency; } @SuppressWarnings("unused") public void handleMessage(int value) throws Exception { logger.debug("Handling: [" + value + "], fails:" + count); if (value % failFrequency == 0) { count.getAndIncrement(); logger.debug("Failing: [" + value + "], fails:" + count); throw new RuntimeException("Planned"); } } public int getCount() { return count.get(); } } }
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()); } }
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); } }
/** * Try passive declaration first, in case the user has pre-configured the queue with incompatible * arguments. * * @param queue The queue. */ private void declareQueueIfNotPresent(Queue queue) { if (this.rabbitAdmin.getQueueProperties(queue.getName()) == null) { this.rabbitAdmin.declareQueue(queue); } }