title: Ensure that AMQP exchange exists before publishing a message to it
body: <h1>Problem</h1>
  
  <p>A Java application uses RabbitMQ and client library <code>com.rabbitmq:amqp-client</code> to connect to it. The application declares an AMQP exchange during initialization and periodically publishes messages to it. </p>
  
  <p><strong>If that exchange gets removed for some reason the application cannot publish messages to it and the AMQP channel gets automatically closed by the library</strong>. So any subsequent publishes (even after the exchange is re-created) fail with such exception:</p>
  
  <pre><code>Exception in thread "main" com.rabbitmq.client.AlreadyClosedException: channel is already closed due to channel error; protocol method: #method&lt;channel.close&gt;(reply-code=404, reply-text=NOT_FOUND - no exchange 'logs' in vhost '/', class-id=60, method-id=40)
  at com.rabbitmq.client.impl.AMQChannel.ensureIsOpen(AMQChannel.java:195)
  at com.rabbitmq.client.impl.AMQChannel.transmit(AMQChannel.java:296)
  at com.rabbitmq.client.impl.ChannelN.basicPublish(ChannelN.java:648)
  at com.rabbitmq.client.impl.ChannelN.basicPublish(ChannelN.java:631)
  at com.rabbitmq.client.impl.ChannelN.basicPublish(ChannelN.java:622)
  </code></pre>
  
  <p>How can I guarantee that the exchange does exist before publish? I see the following options.</p>
  
  <h1>Possible solutions</h1>
  
  <h2>1. Try to re-declare exchange before each publish explicitly</h2>
  
  <p>Thanks to the fact that <code>exchangeDeclare</code> is idempotent and has no effect if the exchange is already in place I could explicitly declare the exchange before any publish:</p>
  
  <pre><code>channel.exchangeDeclare(EXCHANGE_NAME, "fanout", false, true, null);
  channel.basicPublish(EXCHANGE_NAME, "", MessageProperties.PERSISTENT_TEXT_PLAIN, message);
  </code></pre>
  
  <p>The issue with this code is that it looks stupid because most of the time the exchange is in place and the declaration is just redundant. </p>
  
  <p>Also I'm still be in trouble if the exchange is deleted exactly between declaration and publish.</p>
  
  <h2>2. Verify that exchange does exist via <code>exchangeDeclarePassive</code></h2>
  
  <p>I could use <code>exchangeDeclarePassive</code> to check that the exchange exists before publish but the following obvious method doesn't work:</p>
  
  <pre><code>private static void ensureExchangeExists(Channel channel) throws IOException {
      try {
          channel.exchangeDeclarePassive(EXCHANGE_NAME);
      } catch (Exception e) {
          channel.exchangeDeclare(EXCHANGE_NAME, "fanout", false, true, null);
      }
  }
  </code></pre>
  
  <p>The problem is that if the exchange is missing, <code>exchangeDeclarePassive</code> throws the exception and the channel is closed automatically by the library. So the code in catch block cannot declare the exchange (because it tries to perform an operation on the closed channel).</p>
  
  <p>So I can no longer use single AMQP channel and have to manage them in some way.</p>
  
  <p>Also I'm still in trouble if the exchange is removed between declaration and publish.</p>
  
  <h2>3. Catch exception upon publish</h2>
  
  <p>You cannot just wrap call channel.basicPublish with a try/catch block because if the exchange is missing then no exception is thrown. <a href="https://stackoverflow.com/a/32528788/15647">This answer</a> explains what actually happens in this situation.</p>
  
  <p>But you can register a <code>ShutdownListener</code> that is able to detect when a channel is closed, investigate the reason (via <code>cause.isInitiatedByApplication()</code>/<code>cause.getReason()</code>) and do the necessary action.</p>
  
  <h1>Question</h1>
  
  <p>The question is what is the best way to ensure that AMQP exchange exists before publishing a message to it and why?</p>