Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get Spring RabbitMQ to create a new Queue?

Tags:

In my (limited) experience with rabbit-mq, if you create a new listener for a queue that doesn't exist yet, the queue is automatically created. I'm trying to use the Spring AMQP project with rabbit-mq to set up a listener, and I'm getting an error instead. This is my xml config:

<rabbit:connection-factory id="rabbitConnectionFactory" host="172.16.45.1" username="test" password="password" />  <rabbit:listener-container connection-factory="rabbitConnectionFactory"  >     <rabbit:listener ref="testQueueListener" queue-names="test" /> </rabbit:listener-container>  <bean id="testQueueListener" class="com.levelsbeyond.rabbit.TestQueueListener">  </bean> 

I get this in my RabbitMq logs:

=ERROR REPORT==== 3-May-2013::23:17:24 === connection <0.1652.0>, channel 1 - soft error: {amqp_error,not_found,"no queue 'test' in vhost '/'",'queue.declare'} 

And a similar error from AMQP:

2013-05-03 23:17:24,059 ERROR [org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer] (SimpleAsyncTaskExecutor-1) - Consumer received fatal exception on startup org.springframework.amqp.rabbit.listener.FatalListenerStartupException: Cannot prepare queue for listener. Either the queue doesn't exist or the broker will not allow us to use it. 

It would seem from the stack trace that the queue is getting created in a "passive" mode- Can anyone point out how I would create the queue not using the passive mode so I don't see this error? Or am I missing something else?

like image 504
eric Avatar asked May 04 '13 05:05

eric


People also ask

Can RabbitMQ have multiple queues?

Use multiple queues and consumers Queues are single-threaded in RabbitMQ, and one queue can handle up to about 50 thousand messages. You will achieve better throughput on a multi-core system if you have multiple queues and consumers and if you have as many queues as cores on the underlying node(s).

How does RabbitMQ work with spring boot?

It listens for messages on the spring-boot queue. Because the Receiver class is a POJO, it needs to be wrapped in the MessageListenerAdapter , where you specify that it invokes receiveMessage . JMS queues and AMQP queues have different semantics. For example, JMS sends queued messages to only one consumer.


2 Answers

Older thread, but this still shows up pretty high on Google, so here's some newer information:

2015-11-23

Since Spring 4.2.x with Spring-Messaging and Spring-Amqp 1.4.5.RELEASE and Spring-Rabbit 1.4.5.RELEASE, declaring exchanges, queues and bindings has become very simple through an @Configuration class some annotations:

@EnableRabbit @Configuration @PropertySources({     @PropertySource("classpath:rabbitMq.properties") }) public class RabbitMqConfig {         private static final Logger logger = LoggerFactory.getLogger(RabbitMqConfig.class);      @Value("${rabbitmq.host}")     private String host;      @Value("${rabbitmq.port:5672}")     private int port;      @Value("${rabbitmq.username}")     private String username;      @Value("${rabbitmq.password}")     private String password;      @Bean     public ConnectionFactory connectionFactory() {         CachingConnectionFactory connectionFactory = new CachingConnectionFactory(host, port);         connectionFactory.setUsername(username);         connectionFactory.setPassword(password);          logger.info("Creating connection factory with: " + username + "@" + host + ":" + port);          return connectionFactory;     }      /**      * Required for executing adminstration functions against an AMQP Broker      */     @Bean     public AmqpAdmin amqpAdmin() {         return new RabbitAdmin(connectionFactory());     }      /**      * This queue will be declared. This means it will be created if it does not exist. Once declared, you can do something      * like the following:      *       * @RabbitListener(queues = "#{@myDurableQueue}")      * @Transactional      * public void handleMyDurableQueueMessage(CustomDurableDto myMessage) {      *    // Anything you want! This can also return a non-void which will queue it back in to the queue attached to @RabbitListener      * }      */     @Bean     public Queue myDurableQueue() {         // This queue has the following properties:         // name: my_durable         // durable: true         // exclusive: false         // auto_delete: false         return new Queue("my_durable", true, false, false);     }      /**      * The following is a complete declaration of an exchange, a queue and a exchange-queue binding      */     @Bean     public TopicExchange emailExchange() {         return new TopicExchange("email", true, false);     }      @Bean     public Queue inboundEmailQueue() {         return new Queue("email_inbound", true, false, false);     }      @Bean     public Binding inboundEmailExchangeBinding() {         // Important part is the routing key -- this is just an example         return BindingBuilder.bind(inboundEmailQueue()).to(emailExchange()).with("from.*");     } } 

Some sources and documentation to help:

  1. Spring annotations
  2. Declaring/configuration RabbitMQ for queue/binding support
  3. Direct exchange binding (for when routing key doesn't matter)

Note: Looks like I missed a version -- starting with Spring AMQP 1.5, things get even easier as you can declare the full binding right at the listener!

like image 154
Jaymes Bearden Avatar answered Oct 21 '22 22:10

Jaymes Bearden


What seemed to resolve my issue was adding an admin. Here is my xml:

<rabbit:listener-container connection-factory="rabbitConnectionFactory"  >     <rabbit:listener ref="orderQueueListener" queues="test.order" /> </rabbit:listener-container>  <rabbit:queue name="test.order"></rabbit:queue>  <rabbit:admin id="amqpAdmin" connection-factory="rabbitConnectionFactory"/>  <bean id="orderQueueListener" class="com.levelsbeyond.rabbit.OrderQueueListener">    </bean> 
like image 33
eric Avatar answered Oct 21 '22 23:10

eric