<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<html>
<head>
<title>ActiveMQ Artemis No Consumer Buffering Example</title>
<link rel="stylesheet" type="text/css" href="../common/common.css" />
<link rel="stylesheet" type="text/css" href="../common/prettify.css" />
<script type="text/javascript" src="../common/prettify.js"></script>
</head>
<body onload="prettyPrint()">
<h1>No Consumer Buffering Example</h1>
<p>By default, ActiveMQ Artemis consumers buffer messages from the server in a client side buffer
before actual delivery actually occurs.</p>
<p>This improves performance since otherwise every time you called receive() or had processed the last
message in a MessageListener onMessage() method, the ActiveMQ Artemis client would have to go the
server to request the next message involving a network round trip for every message reducing performance.</p>
<p>Therefore, by default, ActiveMQ Artemis pre-fetches messages into a buffer on each consumer. The total maximum size of
messages in bytes that will be buffered on each consumer is determined by the <code>consumer-window-size</code>
parameter on the connection factory.</p>
<p>In some cases it is not desirable to buffer any messages on the client side consumer.</p>
<p>An example would be an order queue which had multiple consumers that processed orders from the queue.
Each order takes a significant time to process, but each one should be processed in a timely fashion.</p>
<p>If orders were buffered in each consumer, and a new consumer was added that consumer would not be able
to process orders which were already in the client side buffer of another consumer.</p>
<p>To turn off client side buffering of messages, set <code>consumer-window-size</code> to zero.</p>
<p>With ActiveMQ Artemis you can specify a maximum consume rate at which a JMS MessageConsumer will consume messages.
This can be specified when creating or deploying the connection factory. See <code>activemq-jms.xml</code></p>
<h2>Example step-by-step</h2>
<p>In this example we specify a <code>consumer-window-size</code> of <code>0</code> bytes in the <code>activemq-jms.xml</code>
file when deploying the connection factory:</p>
<pre class="prettyprint">
<code>
<connection-factory name="ConnectionFactory">
<connector-ref connector-name="netty-connector"/>
<entries>
<entry name="ConnectionFactory"/>
</entries>
<!-- We set the consumer window size to 0, which means messages are not buffered at all
on the client side -->
<consumer-window-size>0</consumer-window-size>
</connection-factory>
</code>
</pre>
<p>We create a consumer on a queue and send 10 messages to it. We then create another consumer on
the same queue.</p>
<p>We then consume messages from each consumer in a semi-random order. We note that the messages
are consumed in the order they were sent.</p>
<p>If the messages had been buffered in each consumer they would not be available to be consumed
in an order determined afer delivery.</p>
<p><i>To run the example, simply type <code>mvn verify -Pexample</code> from this directory</i></p>
<ol>
<li>Create an initial context to perform the JNDI lookup.</li>
<pre class="prettyprint">
<code>initialContext = getContext(0);</code>
</pre>
<li>Perfom a lookup on the queue</li>
<pre class="prettyprint">
<code>Queue queue = (Queue)initialContext.lookup("/queue/exampleQueue");</code>
</pre>
<li>Perform a lookup on the Connection Factory</li>
<pre class="prettyprint">
<code>ConnectionFactory cf = (ConnectionFactory)initialContext.lookup("/ConnectionFactory");</code>
</pre>
<li>Create a JMS Connection</li>
<pre class="prettyprint">
<code>connection = cf.createConnection();</code>
</pre>
<li>Create a JMS Session</li>
<pre class="prettyprint">
<code>Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);</code>
</pre>
<li>Create a JMS MessageProducer</li>
<pre class="prettyprint">
<code>MessageProducer producer = session.createProducer(queue);</code>
</pre>
<li>Create a JMS MessageConsumer</li>
<pre class="prettyprint">
<code>MessageConsumer consumer1 = session.createConsumer(queue);</code>
</pre>
<li>Start the connection</li>
<pre class="prettyprint">
<code>
connection.start();
</code>
</pre>
<li>Send 10 messages to the queue</li>
<pre class="prettyprint">
<code>
final int numMessages = 10;
for (int i = 0; i < numMessages; i++)
{
TextMessage message = session.createTextMessage("This is text message: " + i);
producer.send(message);
}
</code>
</pre>
<li>Create another JMS MessageConsumer on the same queue.</li>
<pre class="prettyprint">
<code>MessageConsumer consumer2 = session.createConsumer(queue);</code>
</pre>
<li>Consume three messages from consumer2</li>
<pre class="prettyprint">
<code>
for (int i = 0; i < 3; i++)
{
TextMessage message = (TextMessage)consumer2.receive(2000);
System.out.println("Consumed message from consumer2: " + message.getText());
}
</code>
</pre>
<li>Consume five messages from consumer1</li>
<pre class="prettyprint">
<code>
for (int i = 0; i < 5; i++)
{
TextMessage message = (TextMessage)consumer1.receive(2000);
System.out.println("Consumed message from consumer1: " + message.getText());
}
</code>
</pre>
<li>Consume two more messages from consumer2</li>
<pre class="prettyprint">
<code>
for (int i = 0; i < 2; i++)
{
TextMessage message = (TextMessage)consumer1.receive(2000);
System.out.println("Consumed message from consumer2: " + message.getText());
}
</code>
</pre>
<li>Be sure to close our resources!</li>
<pre class="prettyprint">
<code>
finally
{
if (initialContext != null)
{
initialContext.close();
}
if (connection != null)
{
connection.close();
}
}</code>
</pre>
</ol>
<h2>More information</h2>
<ul>
<li>User Manual's <a href="../../../docs/user-manual/en/html_single/index.html#flow-control.consumer.window">Consumer Window-Based Flow Control chapter</a></li>
</ul>
</body>
</html>