title: Performance difference between RabbitTemplate's waitForConfirms and blocking correlation data callback
body: <p>I am implementing a service that needs to publish messages to a RabbitMQ broker in a <strong>reliable and blocking</strong> way. As described in <a href="https://www.rabbitmq.com/tutorials/tutorial-seven-java.html" rel="nofollow noreferrer">https://www.rabbitmq.com/tutorials/tutorial-seven-java.html</a>, there are multiple options for publisher confirmation. The most basic option is to use <code>waitForConfirms</code>. I tested the following code (with setting <code>cachingConnectionFactory.setPublisherConfirmType(CachingConnectionFactory.ConfirmType.SIMPLE)</code>) and it took about 100 seconds to publish 10,000 of these messages:</p>
  <pre class="lang-java prettyprint-override"><code>rabbitTemplate.invoke(rabbitOperations -&gt; {
    rabbitOperations.convertAndSend(&quot;test_exchange&quot;, &quot;test_key&quot;, &quot;test message&quot;);
    return rabbitOperations.waitForConfirms(1000);
  });
  </code></pre>
  <p>I also tested the asynchronous option (with setting <code>cachingConnectionFactory.setPublisherConfirmType(CachingConnectionFactory.ConfirmType.CORRELATED)</code>) with a very primitive blocking wrapper. The following code took about 20 seconds to publish 10,000 messages:</p>
  <pre class="lang-java prettyprint-override"><code>CountDownLatch latch = new CountDownLatch(1);
  CorrelationData correlationData = new CorrelationData();
  rabbitTemplate.convertAndSend(&quot;test_exchange&quot;, &quot;test_key&quot;, &quot;test message&quot;, correlationData);
  correlationData.getFuture().addCallback(success -&gt; {
    latch.countDown();
  }, failure -&gt; {
    latch.countDown();
  });
  latch.await();
  </code></pre>
  <p>As far as I understand the following quote in the above link, my first example should basically do the same that my second example does.</p>
  <blockquote>
  <p>Think of waitForConfirmsOrDie as a synchronous helper which relies on asynchronous notifications under the hood.</p>
  </blockquote>
  <p>But the performance difference is too massive for my assumption to be true. I see that <code>RabbitTemplate.invoke</code> executes a lot more stuff than my second code example. But what exactly is the reason for this massive performance difference? Is my second example bad practice, or is my first example in some unnecessary way inefficient?</p>
  <p><strong>EDIT</strong>
  Copy-pasting the code from Gary, I experienced the following:</p>
  <pre><code>StopWatch '': running time = 106379462700 ns
  ---------------------------------------------
  ns         %     Task name
  ---------------------------------------------
  17546479900  016 %  correlated
  88832982800  084 %  simple
  </code></pre>
  <p>I am using Windows 10 Pro, RabbitMQ 3.8.9 running via <code>docker run -it --rm --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-management</code>, and Spring Boot 2.3.1</p>
  <p><strong>EDIT 2</strong>
  Adding <code>RabbitUtils.isPhysicalCloseRequired()</code> to the simple confirmation code of Gary:</p>
  <pre class="lang-java prettyprint-override"><code>simpleTemplate.invoke(ops -&gt; {
    ops.convertAndSend(&quot;so64857773&quot;, &quot;test message&quot;);
    RabbitUtils.isPhysicalCloseRequired();
    return ops.waitForConfirms(1000);
  });
  </code></pre>
  <p>yields the following results:</p>
  <pre><code>StopWatch '': running time = 46090067400 ns
  ---------------------------------------------
  ns         %     Task name
  ---------------------------------------------
  21100935900  046 %  correlated
  24989131500  054 %  simple
  </code></pre>
  <p>It seems that when running a dockerized version of RabbitMQ on Windows, closing and recreating a channel is quite expensive.</p>
  <p><strong>EDIT 3</strong>
  Using a native Windows 10 RabbitMQ server (3.8.9) with Erlang 23.1.3, performance massively increased. Using 10k messages, the correlated confirm test took only around 3 seconds. I increased the number of messages for the following two tests to 50k.</p>
  <p>First test, with the original code from Gary:</p>
  <pre><code>StopWatch '': running time = 144403128200 ns
  ---------------------------------------------
  ns         %     Task name
  ---------------------------------------------
  19750222900  014 %  correlated
  124652905300  086 %  simple
  </code></pre>
  <p>Second test, with <code>RabbitUtils.isPhysicalCloseRequired()</code> added as described in EDIT 2:</p>
  <pre><code>StopWatch '': running time = 30030523500 ns
  ---------------------------------------------
  ns         %     Task name
  ---------------------------------------------
  14549132300  048 %  correlated
  15481391200  052 %  simple
  </code></pre>
  <p>Closing and reopening a channel seems to be very expensive on Windows - it does not seem to be a problem with using the dockerized version.</p>