This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git


The following commit(s) were added to refs/heads/master by this push:
     new 15b0b0fffa ENHANCEMENT + DOCUMENTATION Performance / reliability 
setting for RabbitMQ quorum queues (#2121)
15b0b0fffa is described below

commit 15b0b0fffac0bcbb460687cee23d108aaba179df
Author: Benoit TELLIER <btell...@linagora.com>
AuthorDate: Fri Mar 15 14:29:33 2024 +0100

    ENHANCEMENT + DOCUMENTATION Performance / reliability setting for RabbitMQ 
quorum queues (#2121)
    
    * [ENHANCEMENT] Rabbit Quorum queue: set delivery limits
    
    Setting a delivery limit can prevent RabbitMQ outage if
    message processing fails.
    Read https://www.rabbitmq.com/docs/quorum-queues#poison-message-handling
    
    * [ENHANCEMENT] Rabbit Quorum queue: document performance setting
    
    Was advised on gitter
    ---------
    
    Co-authored-by: Rene Cordier <rcord...@linagora.com>
---
 .../james/backends/rabbitmq/QueueArguments.java    |  5 ++++
 .../backends/rabbitmq/RabbitMQConfiguration.java   | 29 ++++++++++++++++++++--
 .../modules/ROOT/pages/configure/rabbitmq.adoc     | 19 ++++++++++++++
 src/site/xdoc/server/config-rabbitmq.xml           | 18 ++++++++++++++
 4 files changed, 69 insertions(+), 2 deletions(-)

diff --git 
a/backends-common/rabbitmq/src/main/java/org/apache/james/backends/rabbitmq/QueueArguments.java
 
b/backends-common/rabbitmq/src/main/java/org/apache/james/backends/rabbitmq/QueueArguments.java
index 62a7c86e70..5d782d059a 100644
--- 
a/backends-common/rabbitmq/src/main/java/org/apache/james/backends/rabbitmq/QueueArguments.java
+++ 
b/backends-common/rabbitmq/src/main/java/org/apache/james/backends/rabbitmq/QueueArguments.java
@@ -65,6 +65,11 @@ public class QueueArguments {
             return this;
         }
 
+        public Builder deliveryLimit(long deliveryLimit) {
+            arguments.put("x-delivery-limit", deliveryLimit);
+            return this;
+        }
+
         public ImmutableMap<String, Object> build() {
             return arguments.build();
         }
diff --git 
a/backends-common/rabbitmq/src/main/java/org/apache/james/backends/rabbitmq/RabbitMQConfiguration.java
 
b/backends-common/rabbitmq/src/main/java/org/apache/james/backends/rabbitmq/RabbitMQConfiguration.java
index c7963e27d0..092804891e 100644
--- 
a/backends-common/rabbitmq/src/main/java/org/apache/james/backends/rabbitmq/RabbitMQConfiguration.java
+++ 
b/backends-common/rabbitmq/src/main/java/org/apache/james/backends/rabbitmq/RabbitMQConfiguration.java
@@ -307,6 +307,7 @@ public class RabbitMQConfiguration {
     private static final String SSL_KEY_STORE_PATH = "ssl.keystore";
     private static final String SSL_KEY_STORE_PASSWORD = 
"ssl.keystore.password";
     private static final String QUEUE_TTL = "notification.queue.ttl";
+    private static final String QUEUE_DELIVERY_LIMIT = 
"quorum.queues.delivery.limit";
     private static final String EVENT_BUS_NOTIFICATION_DURABILITY_ENABLED = 
"event.bus.notification.durability.enabled";
     private static final String EVENT_BUS_PUBLISH_CONFIRM_ENABLED = 
"event.bus.publish.confirm.enabled";
     private static final String TASK_QUEUE_CONSUMER_TIMEOUT = 
"task.queue.consumer.timeout";
@@ -403,6 +404,7 @@ public class RabbitMQConfiguration {
         private Optional<Boolean> useSsl;
         private Optional<Boolean> useSslManagement;
         private Optional<Boolean> useQuorumQueues;
+        private Optional<Integer> quorumQueueDeliveryLimit;
         private Optional<Integer> quorumQueueReplicationFactor;
         private Optional<SSLConfiguration> sslConfiguration;
         private Optional<Long> queueTTL;
@@ -426,6 +428,7 @@ public class RabbitMQConfiguration {
             this.useSslManagement = Optional.empty();
             this.sslConfiguration = Optional.empty();
             this.useQuorumQueues = Optional.empty();
+            this.quorumQueueDeliveryLimit = Optional.empty();
             this.quorumQueueReplicationFactor = Optional.empty();
             this.hosts = ImmutableList.builder();
             this.queueTTL = Optional.empty();
@@ -445,6 +448,17 @@ public class RabbitMQConfiguration {
             return this;
         }
 
+        public Builder quorumQueueDeliveryLimit(int limit) {
+            Preconditions.checkArgument(limit > 0, "'quorumQueueDeliveryLimit' 
should be strictly positive");
+            this.quorumQueueDeliveryLimit = Optional.of(limit);
+            return this;
+        }
+
+        public Builder quorumQueueDeliveryLimit(Optional<Integer> limit) {
+            limit.ifPresent(this::quorumQueueDeliveryLimit);
+            return this;
+        }
+
         public Builder connectionTimeoutInMs(int connectionTimeout) {
             this.connectionTimeoutInMs = Optional.of(connectionTimeout);
             return this;
@@ -551,6 +565,7 @@ public class RabbitMQConfiguration {
                     useSslManagement.orElse(false),
                     sslConfiguration.orElse(defaultBehavior()),
                     useQuorumQueues.orElse(false),
+                    quorumQueueDeliveryLimit,
                     
quorumQueueReplicationFactor.orElse(DEFAULT_QUORUM_QUEUE_REPLICATION_FACTOR),
                     hostsDefaultingToUri(),
                     queueTTL,
@@ -605,6 +620,7 @@ public class RabbitMQConfiguration {
             .orElse(ImmutableList.of());
 
         Optional<Long> queueTTL = 
Optional.ofNullable(configuration.getLong(QUEUE_TTL, null));
+        Optional<Integer> quorumQueueDeliveryLimit = 
Optional.ofNullable(configuration.getInteger(QUEUE_DELIVERY_LIMIT, null));
 
         Optional<String> vhost = 
Optional.ofNullable(configuration.getString(VHOST, null));
 
@@ -622,6 +638,7 @@ public class RabbitMQConfiguration {
             .sslConfiguration(sslConfiguration(configuration))
             .useQuorumQueues(useQuorumQueues)
             .quorumQueueReplicationFactor(quorumQueueReplicationFactor)
+            .quorumQueueDeliveryLimit(quorumQueueDeliveryLimit)
             .hosts(hosts)
             .queueTTL(queueTTL)
             
.eventBusNotificationDurabilityEnabled(configuration.getBoolean(EVENT_BUS_NOTIFICATION_DURABILITY_ENABLED,
 null))
@@ -692,6 +709,7 @@ public class RabbitMQConfiguration {
     private final Boolean useSslManagement;
     private final SSLConfiguration sslConfiguration;
     private final boolean useQuorumQueues;
+    private final Optional<Integer> quorumQueueDeliveryLimit;
     private final int quorumQueueReplicationFactor;
     private final List<Host> hosts;
     private final ManagementCredentials managementCredentials;
@@ -704,7 +722,7 @@ public class RabbitMQConfiguration {
     private RabbitMQConfiguration(URI uri, URI managementUri, 
ManagementCredentials managementCredentials, int maxRetries, int minDelayInMs,
                                   int connectionTimeoutInMs, int 
channelRpcTimeoutInMs, int handshakeTimeoutInMs, int shutdownTimeoutInMs,
                                   int networkRecoveryIntervalInMs, Boolean 
useSsl, Boolean useSslManagement, SSLConfiguration sslConfiguration,
-                                  boolean useQuorumQueues, int 
quorumQueueReplicationFactor, List<Host> hosts, Optional<Long> queueTTL,
+                                  boolean useQuorumQueues, Optional<Integer> 
quorumQueueDeliveryLimit, int quorumQueueReplicationFactor, List<Host> hosts, 
Optional<Long> queueTTL,
                                   boolean eventBusPublishConfirmEnabled, 
boolean eventBusNotificationDurabilityEnabled,
                                   Optional<String> vhost, Duration 
taskQueueConsumerTimeout) {
         this.uri = uri;
@@ -721,6 +739,7 @@ public class RabbitMQConfiguration {
         this.useSslManagement = useSslManagement;
         this.sslConfiguration = sslConfiguration;
         this.useQuorumQueues = useQuorumQueues;
+        this.quorumQueueDeliveryLimit = quorumQueueDeliveryLimit;
         this.quorumQueueReplicationFactor = quorumQueueReplicationFactor;
         this.hosts = hosts;
         this.queueTTL = queueTTL;
@@ -786,6 +805,7 @@ public class RabbitMQConfiguration {
         QueueArguments.Builder builder = QueueArguments.builder();
         if (allowQuorum && useQuorumQueues) {
             
builder.quorumQueue().replicationFactor(quorumQueueReplicationFactor);
+            quorumQueueDeliveryLimit.ifPresent(builder::deliveryLimit);
         }
         return builder;
     }
@@ -823,6 +843,10 @@ public class RabbitMQConfiguration {
         return taskQueueConsumerTimeout;
     }
 
+    public Optional<Integer> getQuorumQueueDeliveryLimit() {
+        return quorumQueueDeliveryLimit;
+    }
+
     @Override
     public final boolean equals(Object o) {
         if (o instanceof RabbitMQConfiguration) {
@@ -841,6 +865,7 @@ public class RabbitMQConfiguration {
                 && Objects.equals(this.useSsl, that.useSsl)
                 && Objects.equals(this.useQuorumQueues, that.useQuorumQueues)
                 && Objects.equals(this.quorumQueueReplicationFactor, 
that.quorumQueueReplicationFactor)
+                && Objects.equals(this.quorumQueueDeliveryLimit, 
that.quorumQueueDeliveryLimit)
                 && Objects.equals(this.useSslManagement, that.useSslManagement)
                 && Objects.equals(this.sslConfiguration, that.sslConfiguration)
                 && Objects.equals(this.hosts, that.hosts)
@@ -855,7 +880,7 @@ public class RabbitMQConfiguration {
 
     @Override
     public final int hashCode() {
-        return Objects.hash(uri, managementUri, maxRetries, minDelayInMs, 
connectionTimeoutInMs, quorumQueueReplicationFactor, useQuorumQueues, hosts,
+        return Objects.hash(uri, managementUri, maxRetries, minDelayInMs, 
connectionTimeoutInMs, quorumQueueReplicationFactor, quorumQueueDeliveryLimit, 
useQuorumQueues, hosts,
             channelRpcTimeoutInMs, handshakeTimeoutInMs, shutdownTimeoutInMs, 
networkRecoveryIntervalInMs, managementCredentials, useSsl, useSslManagement,
             sslConfiguration, queueTTL, eventBusPublishConfirmEnabled, 
eventBusNotificationDurabilityEnabled, vhost, taskQueueConsumerTimeout);
     }
diff --git 
a/server/apps/distributed-app/docs/modules/ROOT/pages/configure/rabbitmq.adoc 
b/server/apps/distributed-app/docs/modules/ROOT/pages/configure/rabbitmq.adoc
index 0910b2d61e..c4089e29c8 100644
--- 
a/server/apps/distributed-app/docs/modules/ROOT/pages/configure/rabbitmq.adoc
+++ 
b/server/apps/distributed-app/docs/modules/ROOT/pages/configure/rabbitmq.adoc
@@ -87,6 +87,10 @@ False (default value) results in the usage of classic queues.
 | quorum.queues.replication.factor
 | Strictly positive integer. The replication factor to use when creating 
quorum queues.
 
+| quorum.queues.delivery.limit
+| Strictly positive integer. Value for x-delivery-limit queue parameter, 
default to none. Setting a delivery limit can
+prevent RabbitMQ outage if message processing fails. Read 
https://www.rabbitmq.com/docs/quorum-queues#poison-message-handling
+
 | hosts
 | Optional, default to the host specified as part of the URI.
 Allow creating cluster aware connections.
@@ -107,6 +111,21 @@ You still need to specify the vhost in the uri parameter.
 
 |===
 
+== Tuning RabbitMQ for quorum queue use
+
+While quorum queues are great at preserving your data and enabling High 
Availability, they demand more resources and
+a greater care than regular RabbitMQ queues.
+
+See link:https://www.rabbitmq.com/docs/quorum-queues#performance-tuning[this 
section of RabbitMQ documentation regarding RabbitMQ quroum queue performance 
tunning].
+
+ - Provide decent amount of RAM memory to RabbitMQ. 4GB is a good start.
+ - Setting a delivery limit is advised as looping messages can cause extreme 
memory consumptions onto quorum queues.
+ - Set up Raft for small messages:
+
+....
+raft.segment_max_entries = 32768
+....
+
 == RabbitMQ MailQueue Configuration
 
 James mail queue is a component acting like a queue where it can enqueue and 
dequeue mails.
diff --git a/src/site/xdoc/server/config-rabbitmq.xml 
b/src/site/xdoc/server/config-rabbitmq.xml
index 6bbf9a6ea9..cc651d1ef7 100644
--- a/src/site/xdoc/server/config-rabbitmq.xml
+++ b/src/site/xdoc/server/config-rabbitmq.xml
@@ -120,6 +120,10 @@
           <dt><strong>quorum.queues.replication.factor</strong></dt>
           <dd> Strictly positive integer. The replication factor to use when 
creating quorum queues.</dd>
 
+          <dt><strong>quorum.queues.delivery.limit</strong></dt>
+          <dd> Strictly positive integer. Value for x-delivery-limit queue 
parameter, default to none. Setting a delivery limit can
+          prevent RabbitMQ outage if message processing fails. Read 
https://www.rabbitmq.com/docs/quorum-queues#poison-message-handling</dd>
+
           <dt><strong>hosts</strong></dt>
           <dd>Optional, default to the host specified as part of the URI.
               Allow creating cluster aware connections.
@@ -146,7 +150,21 @@
           </dd>
       </dl>
   </section>
+  <section name="Tuning RabbitMQ for quorum queue use">
+      <p>While quorum queues are great at preserving your data and enabling 
High Availability, they demand more resources and
+          a greater care than regular RabbitMQ queues.</p>
+
+      <p>See <a 
href="https://www.rabbitmq.com/docs/quorum-queues#performance-tuning";>
+          this section of RabbitMQ documentation regarding RabbitMQ quroum 
queue performance tunning</a>.</p>
 
+      <ul>
+          <li>Provide decent amount of RAM memory to RabbitMQ. 4GB is a good 
start.</li>
+          <li>Setting a delivery limit is advised as looping messages can 
cause extreme memory consumptions onto quorum queues.</li>
+          <li>Set up Raft for small messages:</li>
+      </ul>
+
+      <pre><code>raft.segment_max_entries = 32768</code></pre>
+  </section>
   <section name="RabbitMQ MailQueue Configuration">
       <p>
           RabbitMQ MailQueue Configuration


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscr...@james.apache.org
For additional commands, e-mail: notifications-h...@james.apache.org

Reply via email to