Search code examples
javaspringrabbitmqspring-rabbit

Prevent @RabbitListener in spring-rabbit from trying to connect to server during integration test


I want to run some acceptance tests for my services that are using rabbitMq but I want to ignore all that require inter-service communication (amqp).

The problem however is that Spring tries to connect to the (non-exisiting) rabbit host on startup so it can register its consumers. It does that for each method that is annotated with @RabbitListener which can get quite annoying with the long timeout this has if I have more than one listener in my service.

How can I reduce this timeout or even prevent @RabbitListener connection all together?

Our (simplified) Rabbit Config:

@Configuration
@EnableRabbit
public class RabbitMqConfig {

    public RabbitMqConfig(
            @Value("${rabbitmq.host}") String rabbitHost,
            @Value("${rabbitmq.port}") int rabbitPort,
            @Value("${exchange.name}") String exchange) {
        this.rabbitHost = rabbitHost;
        this.rabbitPort = rabbitPort;
        this.exchange= exchange;
    }

  @Bean
  DirectExchange directExchangeBean() {
    return new DirectExchange(this.exchange, true, false);
  }

  @Bean
  public ConnectionFactory connectionFactory() {
    CachingConnectionFactory connectionFactory = new CachingConnectionFactory(rabbitHost);
    connectionFactory.setPort(rabbitPort);
    return connectionFactory;
  }

  @Bean
  public RabbitTemplate rabbitTemplate() {
    return new RabbitTemplate(connectionFactory());
  }


  @Bean
  public Queue itemDoneQueue() {
    return new Queue(ITEM_DONE_QUEUENAME, true);
  }

  @Bean
  Binding itemDoneBinding() {
    return BindingBuilder.bind(itemDoneQueue()).to(directExchangeBean()).with(ITEM_DONE_KEY);
  }

}

Properties

rabbitmq.host=192.168.42.100
rabbitmq.port=5672
exchange.name=myExchange

The Listener:

  @RabbitListener(queues = ITEM_DONE_QUEUENAME)
  public void receiveMessageFromItemDoneQueue(String message) {
    // do the work
  }

The Test:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {Application.class}) 
public abstract class RabbitTest {

Really nothing special here. Obviously during testing the rabbit host is unavailable. That is fine. I want to ignore the fact. And quickly.

I've tried

spring.rabbitmq.connection-timeout=1

But that didn't change anything.

Using

spring.rabbitmq.listener.simple.auto-startup=false

neither does anything.

Using

spring.autoconfigure.exclude:org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration

just kills my application context loading with spring complaining about a NoSuchBeanDefinitionException: No bean named 'rabbitListenerContainerFactory' available

Any ideas? Thanks!


Solution

  • Thanks for your input Gary. I already found a solution that works for me. For some reason the connection timeout for the Consumer initialization is not exposed in the CachingConnectionFactory I used nor is the property used that I tried (spring.rabbitmq.connection-timeout).

    What I do now is initialize the base ConnectionFactory and pass it to the CachingConnectionFactory (Having of course no clue where the difference is but that is the case most of the time with spring):

      @Bean
      public ConnectionFactory connectionFactory() {
        com.rabbitmq.client.ConnectionFactory connectionFactory = new com.rabbitmq.client.ConnectionFactory();
        connectionFactory.setConnectionTimeout(this.connectionTimeout);
        connectionFactory.setHost(this.rabbitHost);
        connectionFactory.setPort(this.rabbitPort);
        CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory(
            connectionFactory);
        return cachingConnectionFactory;
      }
    

    Now I can set the timeout to 1 during my acceptence tests causing the consumer initialization to fail quickly and to a higher value for deployment.