I've got a series of tomcat/spring applications for which messages need to be sent from single instances of several different servers to numerous clients, using a couple of different fanout exchanges. Each server instance has its own set of exchanges. The exchanges are declared by the server, and anonymous queues generated by each client and bound to those exchanges. I'm using anonymous queues because I don't know in advance how many consumers there will be, and of course I can't bind multiple consumers to a single named queue without undermining the nature of the fanout exchange. On the client side, I'm getting a ton of exceptions in my logs relating to attempts to re-declare or delete these anonymous queues.
To paint a clearer picture: Imagine I've got 2 services, Service A and Service B, each of which publishes to a pair of fanout exchanges - say ExchangeA1, ExchangeA2 for service A, and ExchangeB1, ExchangeB2 for service B. Now imagine I've got a single client establishing randomly-named queues bound to each of those 4 exchanges so it can monitor messages from both services.
Messages are sent successfully from the server-side to the exchanges without issue, so I'll leave off the server-side config, though I can provide that if it becomes relevant. Here's the client-side spring-config:
<rabbit:queue id="ClientQ1" />
<rabbit:queue id="ClientQ2" />
<!-- declare the exchanges so we can bind to them -->
<rabbit:fanout-exchange id="ExchangeA1.id" name="ExchangeA1">
<rabbit:bindings>
<rabbit:binding queue="ClientQ1"/>
</rabbit:bindings>
</rabbit:fanout-exchange>
<rabbit:fanout-exchange id="ExchangeA2.id" name="ExchangeA2">
<rabbit:bindings>
<rabbit:binding queue="ClientQ2"/>
</rabbit:bindings>
</rabbit:fanout-exchange>
<rabbit:connection-factory id="rabbitConnectionFactory" <!-- this is a simple singleton bean that establishes an SSL connection to rabbitmq -->
connection-factory="rabbitMQConnectionFactoryBean"
publisher-confirms="true"
channel-cache-size="5" />
<rabbit:admin id="myRabbitAdmin" connection-factory="rabbitConnectionFactory"/>
<rabbit:listener-container id="rabbitListenerContainer"
acknowledge="auto"
prefetch="1000"
connection-factory="rabbitConnectionFactory"
message-converter="EventMessageConverterBean" >
<rabbit:listener ref="Q1ListenerBean"
admin="myRabbitAdmin"
method="processEvent"
queue-names="#{ClientQ1.name}" />
<rabbit:listener ref="Q2ListenerBean"
admin="myRabbitAdmin"
method="processEvent"
queue-names="#{ClientQ2.name}" />
</rabbit:listener-container>
Now, imagine that in some other dependency of this client, the same configuration is essentially repeated for bindings to ExchangeB(1,2).
Upon startup, I'm seeing loads of exceptions following this pattern:
ERROR - SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(1158) | Consumer received fatal exception on startup
org.springframework.amqp.rabbit.listener.QueuesNotAvailableException: Cannot prepare queue for listener. Either the queue doesn't exist or the broker will not allow us to use it.
at org.springframework.amqp.rabbit.listener.BlockingQueueConsumer.start(BlockingQueueConsumer.java:481)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1083)
at java.lang.Thread.run(Thread.java:748)
Caused by: org.springframework.amqp.rabbit.listener.BlockingQueueConsumer$DeclarationException: Failed to declare queue(s):[e4d2b49c-140f-4893-a764-4c84f945d482]
at org.springframework.amqp.rabbit.listener.BlockingQueueConsumer.attemptPassiveDeclarations(BlockingQueueConsumer.java:554)
at org.springframework.amqp.rabbit.listener.BlockingQueueConsumer.start(BlockingQueueConsumer.java:453)
... 2 more
Caused by: java.io.IOException
at com.rabbitmq.client.impl.AMQChannel.wrap(AMQChannel.java:106)
at com.rabbitmq.client.impl.AMQChannel.wrap(AMQChannel.java:102)
at com.rabbitmq.client.impl.AMQChannel.exnWrappingRpc(AMQChannel.java:124)
at com.rabbitmq.client.impl.ChannelN.queueDeclarePassive(ChannelN.java:801)
at com.rabbitmq.client.impl.ChannelN.queueDeclarePassive(ChannelN.java:61)
at sun.reflect.GeneratedMethodAccessor56.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.amqp.rabbit.connection.CachingConnectionFactory$CachedChannelInvocationHandler.invoke(CachingConnectionFactory.java:666)
at com.sun.proxy.$Proxy114.queueDeclarePassive(Unknown Source)
at org.springframework.amqp.rabbit.listener.BlockingQueueConsumer.attemptPassiveDeclarations(BlockingQueueConsumer.java:533)
... 3 more
Caused by: com.rabbitmq.client.ShutdownSignalException: channel error; protocol method: #method<channel.close>(reply-code=405, reply-text=RESOURCE_LOCKED - cannot obtain exclusive access to locked queue 'e4d2b49c-140f-4893-a764-4c84f945d482' in vhost '/', class-id=50, method-id=10)
at com.rabbitmq.utility.ValueOrException.getValue(ValueOrException.java:67)
at com.rabbitmq.utility.BlockingValueOrException.uninterruptibleGetValue(BlockingValueOrException.java:33)
at com.rabbitmq.client.impl.AMQChannel$BlockingRpcContinuation.getReply(AMQChannel.java:343)
at com.rabbitmq.client.impl.AMQChannel.privateRpc(AMQChannel.java:216)
at com.rabbitmq.client.impl.AMQChannel.exnWrappingRpc(AMQChannel.java:118)
... 11 more
My debugging has lead me to the redeclareElementsIfNecessary() method in SimpleMessageListenerContainer(:954), which attempts to redeclare all queues/exhcnages/bindings if any are missing. This fails because rabbitmq will not allow exclusive queues to be redelcared. (or so I think)
Searching for similar issues lead me to this: Spring AMQP v1.4.2 - Rabbit reconnection issue on network failure , which is tangentially related, but the solution is not applicable to my problem. Since anonymous queues are by nature exclusive, and I must use anonymous queues, I seem to be stuck between a rock and a hard place. My questions are these:
- Am I doing something wrong w/r/t my listener configuration? Could I change my configuration in some way i'm missing that would alleviate this problem?
- Why is redeclareElementsIfNecessary being invoked? It seems to me that all of the queues in question should exist after the first declaration.
- Are these errors truly innocuous? If so, how can I go about intercepting them to avoid all the exceptions showing up in my logs?
Any information would be appreciated.
spring-amqp 1.4.6
rabbitmq 3.6.10
Update 1 Some relevant spring-debug log output related to rabbit:admin:
17:22:14,783 DEBUG RabbitAdmin:382 - Initializing declarations
17:22:14,784 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'serviceAExchange1'
17:22:14,784 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'serviceAExchange2'
17:22:14,784 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'serviceBExchange1'
17:22:14,784 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'serviceBExchange2'
17:22:14,784 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'org.springframework.amqp.core.TopicExchange#0'
17:22:14,784 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'org.springframework.amqp.core.TopicExchange#1'
17:22:14,784 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'org.springframework.amqp.core.TopicExchange#2'
17:22:14,784 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'ServiceAQueue1'
17:22:14,784 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'ServiceAQueue2'
17:22:14,784 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'ServiceBQueue1'
17:22:14,784 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'ServiceBQueue2'
17:22:14,784 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'consumer.index.amqp.consumerQueue'
17:22:14,785 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'org.springframework.amqp.rabbit.config.BindingFactoryBean#0'
17:22:14,785 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'org.springframework.amqp.rabbit.config.BindingFactoryBean#1'
17:22:14,786 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'org.springframework.amqp.rabbit.config.BindingFactoryBean#2'
17:22:14,786 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'org.springframework.amqp.rabbit.config.BindingFactoryBean#3'
17:22:14,786 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'org.springframework.amqp.rabbit.config.BindingFactoryBean#4'
17:22:14,786 INFO RabbitAdmin:399 - Auto-declaring a non-durable, auto-delete, or exclusive Queue (07475112-7be0-4c8d-b6e5-3279e81a1aff) durable:false, auto-delete:true, exclusive:true. It will be redeclared if the broker stops and is restarted while the connection factory is alive, but all messages will be lost.
17:22:14,786 INFO RabbitAdmin:399 - Auto-declaring a non-durable, auto-delete, or exclusive Queue (e4825008-954f-4154-bd61-9b67e0ff582e) durable:false, auto-delete:true, exclusive:true. It will be redeclared if the broker stops and is restarted while the connection factory is alive, but all messages will be lost.
17:22:14,786 INFO RabbitAdmin:399 - Auto-declaring a non-durable, auto-delete, or exclusive Queue (001bd357-6203-49a6-b573-7f1a998ff750) durable:false, auto-delete:true, exclusive:true. It will be redeclared if the broker stops and is restarted while the connection factory is alive, but all messages will be lost.
17:22:14,786 INFO RabbitAdmin:399 - Auto-declaring a non-durable, auto-delete, or exclusive Queue (3880a65f-0104-4c99-96ac-1958ace7e2e0) durable:false, auto-delete:true, exclusive:true. It will be redeclared if the broker stops and is restarted while the connection factory is alive, but all messages will be lost.
17:22:14,786 INFO RabbitAdmin:399 - Auto-declaring a non-durable, auto-delete, or exclusive Queue (3b1bc32a-872e-4fc3-ba2a-de200bc7b758) durable:false, auto-delete:true, exclusive:true. It will be redeclared if the broker stops and is restarted while the connection factory is alive, but all messages will be lost.
17:22:14,791 INFO CachingConnectionFactory:213 - Created new connection: SimpleConnection@3158bf2b [delegate=amqp://[email protected]:5671/]
17:22:14,791 DEBUG RabbitAdmin:382 - Initializing declarations
17:22:14,791 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'serviceAExchange1'
17:22:14,791 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'serviceAExchange2'
17:22:14,791 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'serviceBExchange1'
17:22:14,791 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'serviceBExchange2'
17:22:14,791 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'org.springframework.amqp.core.TopicExchange#0'
17:22:14,792 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'org.springframework.amqp.core.TopicExchange#1'
17:22:14,792 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'org.springframework.amqp.core.TopicExchange#2'
17:22:14,792 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'ServiceAQueue1'
17:22:14,792 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'ServiceAQueue2'
17:22:14,792 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'ServiceBQueue1'
17:22:14,792 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'ServiceBQueue2'
17:22:14,792 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'consumer.index.amqp.consumerQueue'
17:22:14,792 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'org.springframework.amqp.rabbit.config.BindingFactoryBean#0'
17:22:14,792 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'org.springframework.amqp.rabbit.config.BindingFactoryBean#1'
17:22:14,792 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'org.springframework.amqp.rabbit.config.BindingFactoryBean#2'
17:22:14,792 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'org.springframework.amqp.rabbit.config.BindingFactoryBean#3'
17:22:14,792 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'org.springframework.amqp.rabbit.config.BindingFactoryBean#4'
17:22:14,792 INFO RabbitAdmin:399 - Auto-declaring a non-durable, auto-delete, or exclusive Queue (07475112-7be0-4c8d-b6e5-3279e81a1aff) durable:false, auto-delete:true, exclusive:true. It will be redeclared if the broker stops and is restarted while the connection factory is alive, but all messages will be lost.
17:22:14,792 INFO RabbitAdmin:399 - Auto-declaring a non-durable, auto-delete, or exclusive Queue (e4825008-954f-4154-bd61-9b67e0ff582e) durable:false, auto-delete:true, exclusive:true. It will be redeclared if the broker stops and is restarted while the connection factory is alive, but all messages will be lost.
17:22:14,792 INFO RabbitAdmin:399 - Auto-declaring a non-durable, auto-delete, or exclusive Queue (001bd357-6203-49a6-b573-7f1a998ff750) durable:false, auto-delete:true, exclusive:true. It will be redeclared if the broker stops and is restarted while the connection factory is alive, but all messages will be lost.
17:22:14,792 INFO RabbitAdmin:399 - Auto-declaring a non-durable, auto-delete, or exclusive Queue (3880a65f-0104-4c99-96ac-1958ace7e2e0) durable:false, auto-delete:true, exclusive:true. It will be redeclared if the broker stops and is restarted while the connection factory is alive, but all messages will be lost.
17:22:14,792 INFO RabbitAdmin:399 - Auto-declaring a non-durable, auto-delete, or exclusive Queue (3b1bc32a-872e-4fc3-ba2a-de200bc7b758) durable:false, auto-delete:true, exclusive:true. It will be redeclared if the broker stops and is restarted while the connection factory is alive, but all messages will be lost.
17:22:14,811 DEBUG CachingConnectionFactory:395 - Creating cached Rabbit Channel from PublisherCallbackChannelImpl: AMQChannel(amqp://[email protected]:5671/,1)
17:22:14,811 DEBUG CachingConnectionFactory:395 - Creating cached Rabbit Channel from PublisherCallbackChannelImpl: AMQChannel(amqp://[email protected]:5671/,1)
17:22:14,821 DEBUG RabbitTemplate:1045 - Executing callback on RabbitMQ Channel: Cached Rabbit Channel: PublisherCallbackChannelImpl: AMQChannel(amqp://[email protected]:5671/,1)
17:22:14,821 DEBUG RabbitAdmin:444 - declaring Exchange 'serviceAExchange1'
17:22:14,822 DEBUG RabbitTemplate:1045 - Executing callback on RabbitMQ Channel: Cached Rabbit Channel: PublisherCallbackChannelImpl: AMQChannel(amqp://[email protected]:5671/,1)
17:22:14,825 DEBUG RabbitAdmin:444 - declaring Exchange 'serviceAExchange1'
17:22:14,827 DEBUG RabbitAdmin:444 - declaring Exchange 'serviceAExchange2'
17:22:14,828 DEBUG RabbitAdmin:444 - declaring Exchange 'serviceAExchange2'
17:22:14,829 DEBUG RabbitAdmin:444 - declaring Exchange 'serviceBExchange1'
17:22:14,830 DEBUG RabbitAdmin:444 - declaring Exchange 'serviceBExchange1'
17:22:14,832 DEBUG RabbitAdmin:444 - declaring Exchange 'serviceBExchange2'
17:22:14,835 DEBUG RabbitAdmin:444 - declaring Exchange 'serviceBExchange2'
17:22:14,836 DEBUG RabbitAdmin:472 - declaring Queue '07475112-7be0-4c8d-b6e5-3279e81a1aff'
17:22:14,837 DEBUG RabbitAdmin:472 - declaring Queue '07475112-7be0-4c8d-b6e5-3279e81a1aff'
17:22:14,843 DEBUG RabbitAdmin:472 - declaring Queue 'e4825008-954f-4154-bd61-9b67e0ff582e'
17:22:14,845 DEBUG RabbitAdmin:472 - declaring Queue '001bd357-6203-49a6-b573-7f1a998ff750'
17:22:14,848 DEBUG RabbitAdmin:472 - declaring Queue '3880a65f-0104-4c99-96ac-1958ace7e2e0'
17:22:14,853 DEBUG RabbitAdmin:472 - declaring Queue '3b1bc32a-872e-4fc3-ba2a-de200bc7b758'
17:22:14,856 DEBUG PublisherCallbackChannelImpl:654 - PendingConfirms cleared
17:22:14,856 DEBUG RabbitAdmin:511 - Binding destination [07475112-7be0-4c8d-b6e5-3279e81a1aff (QUEUE)] to exchange [serviceAExchange1] with routing key []
17:22:14,858 ERROR CachingConnectionFactory:292 - Channel shutdown: channel error; protocol method: #method<channel.close>(reply-code=405, reply-text=RESOURCE_LOCKED - cannot obtain exclusive access to locked queue '07475112-7be0-4c8d-b6e5-3279e81a1aff' in vhost '/', class-id=50, method-id=10)
17:22:14,859 DEBUG CachingConnectionFactory:673 - Detected closed channel on exception. Re-initializing: PublisherCallbackChannelImpl: AMQChannel(amqp://[email protected]:5671/,1)
17:22:14,860 DEBUG RabbitAdmin:511 - Binding destination [e4825008-954f-4154-bd61-9b67e0ff582e (QUEUE)] to exchange [serviceAExchange2] with routing key []
17:22:14,862 DEBUG RabbitAdmin:511 - Binding destination [001bd357-6203-49a6-b573-7f1a998ff750 (QUEUE)] to exchange [serviceBExchange1] with routing key []
17:22:14,864 WARN RabbitAdmin:494 - Failed to declare queue:Queue [name=07475112-7be0-4c8d-b6e5-3279e81a1aff, durable=false, autoDelete=true, exclusive=true, arguments=null], continuing...
java.io.IOException
at com.rabbitmq.client.impl.AMQChannel.wrap(AMQChannel.java:106)
[...]
Caused by: com.rabbitmq.client.ShutdownSignalException: channel error; protocol method: #method<channel.close>(reply-code=405, reply-text=RESOURCE_LOCKED - cannot obtain exclusive access to locked queue '07475112-7be0-4c8d-b6e5-3279e81a1aff' in vhost '/', class-id=50, method-id=10)
[ More declaration errors follow ]
17:22:14,836 DEBUG RabbitAdmin:472 - declaring Queue 07475112-7be0-4c8d-b6e5-3279e81a1aff 17:22:14,837 DEBUG RabbitAdmin:472 - declaring Queue 07475112-7be0-4c8d-b6e5-3279e81a1aff'
Exactly this queue is mentioned later in the exception. Maybe you could publish your project on github or bitbucket so we can check the whole configuration. – Sergii Zhevzhyk