RabbitMQ configuration

All config file settings that start with rabbitmq-* control how MailerQ interacts with RabbitMQ. Amongst these settings are the address of the RabbitMQ server, the queue from which outgoing messages are read, and the queues to which incoming messages are delivered.

RabbitMQ address

MailerQ reads the location and authentication information to connect to RabbitMQ from its config file. This data is stored in the "rabbitmq-address" setting:

rabbitmq-address: amqp://login:passwd@hostname/vhost

The format of the address is obvious: the "login" and "passwd" hold the username and password of the RabbitMQ server, the hostname is the name of the server on which RabbitMQ runs, and the optional vhost is the name of the "virtual host" inside RabbitMQ that you have reserved for all MailerQ related data.

If you leave the "rabbitmq-address" setting empty, MailerQ uses the "amqp://guest:guest@localhost/" default value. This default only works if you run RabbitMQ and MailerQ on the same server, and when you do not use a special vhost.

If you have a cluster of RabbitMQ nodes, you can use commas to separate the addresses:

rabbitmq-address: amqp://guest:guest@host1/vhost,amqp://guest:guest@host2/vhost,amqp://guest:guest@host3/vhost

Running a cluster allows you to use highly available queues.

If your RabbitMQ server supports secure connections, you can configure MailerQ to connect to an "amqps://" address instead. The communication between MailerQ and RabbitMQ will then be encrypted.

rabbitmq-address: amqps://guest:guest@hostname/vhost
rabbitmq-verify:  false

MailerQ checks the server certificate when it connects to a secured RabbitMQ server. If this certificate can not be verified with one of the known openssl certificate authorities, MailerQ refuses to set up a connection. If you use a self-signed certificate, you may want to skip this extra test, and set the config file option "rabbitmq-verify" to "false".

Priority queues

RabbitMQ supports priority queues. If you use a priority queue for the outbox, messages with a higher priority are consumed by MailerQ before messages with a lower priority, and are therefore also sent out faster. This could be useful if you want to inject messages that should be sent before emails already queued.

To turn a queue into a priority queue, the queue in RabbitMQ must have been declared with the "x-max-priority" property set. If you declare your own queues, you have to do this yourself. If you rely on MailerQ to declare the queues, you can specify the value of this property in the config file:

rabbitmq-maxpriority: 4

The above config file option instructs MailerQ to set the "x-max-priority" property on the queues it creates. This setting is used during application startup when the queues are declared, and when new temporary queues are declared. If queues already exist, they must match the "x-max-priority" setting of the existing queues.

The reason MailerQ declares all queues to be priority queues is so that messages that are higher priority can be picked up sooner in every part of the chain, also its reports and its results. The same holds for messages that are injected, as they can also have a priority setting set, allowing for injected messages also to be picked up sooner.

In general, this number should be kept as small as possible, as there is a significant overhead for priority queues. For example, when a priority queue is created with an "x-max-priority" of 4, RabbitMQ internally creates 4 queues. As this happens for every queue MailerQ declares, priority queues with more than two or three priority levels are generally discouraged.

Disable startup declarations

All queues and the exchange are automatically created when MailerQ starts. If you do not want MailerQ to declare the queues and exchanges, you can use the "rabbitmq-declare" setting in the config file. If you set this to false, no queues or exchanges are declared on startup.

rabbitmq-declare: false

Disabling the declaration of queues and exchanges is helpful if you have already created them yourself and you do not want MailerQ to do this for you. If you have created the queues with slightly different settings than MailerQ does, you even need this setting because otherwise MailerQ reports a queue incompatibility error and refuses to start.

Persistent and durable settings

In the MailerQ configuration you can specify whether you want queues to be durable and whether you want messages to be persistent using the following two options:

rabbitmq-durable:       true    (default: true)
rabbitmq-persistent:    false   (default: false)
rabbitmq-lazy:          false   (default: false)

MailerQ creates several queues and exchanges in RabbitMQ. When MailerQ starts, it first checks if the queues and exchanges that you have configured in the MailerQ config file exist. If they do not, MailerQ sends instructions to RabbitMQ to create the required exchanges and queues. RabbitMQ allows you to mark your queues and exchanges to be "durable". This means that the exchange or queue will continue to exist even when RabbitMQ is restarted. In theory it is a slightly better to enable durable queues (but you probably won't notice much of a difference because the queues and exchanges are automatically re-created on startup anyway).

The "rabbitmq-persistent" setting toggles whether messages published to RabbitMQ should be cached in main memory or on disk. With the default "false" setting, RabbitMQ keeps messages only in main memory and not on disk. This is much, much faster than storing the messages to disk. It does however bring a higher risk, because if RabbitMQ crashes, the messages will be lost. Turning on persistency will mean your messages are also saved to disk, and can survive a RabbitMQ crash. But at the same time it makes things much slower. We therefore recommend leaving the "rabbitmq-persistent" option off (set to "false"). Note that if you do turn it on, durable queues should also be turned on. Persistent messages are still lost if the queue is not durable, because the queue no longer exists.

The "rabbitmq-lazy" setting toggles whether queues are declared as lazy queues. Lazy queues ensure that messages are always written to disk. This lowers overall performance, but prevents sudden performance drops once RabbitMQ needs to flush to disk, giving predictable performance. See the RabbitMQ documentation for more information on lazy queues.

Multiple threads

MailerQ opens a number of different connections to RabbitMQ, and each connection runs in its own thread. There are separate threads for consuming from the inbox queue and threads for publishing messages to the result queues and/or back to the outbox queue.

You can specify in the config file that you want to start up multiple consumer and/or multiple publisher threads. If you notice that the consumer of publisher threads are CPU bound, you can configure MailerQ to start up more threads.

rabbitmq-consumers:     1 (default: 1)
rabbitmq-publishers:    1 (default: 1)

By adding the "rabbitmq-consumers" and "rabbitmq-publishers" variables to the config file, you instruct MailerQ to start up more consumer and/or publisher threads.

Compression

The data stream between RabbitMQ and MailerQ can be large. It can even be that big that it takes up a significant portion of the capacity of your internal network. To reduce the load on the network, MailerQ supports gzip compression.

MailerQ normally expects messages from RabbitMQ to be JSON encoded. However, if the AMQP envelope in which the message is wrapped has the "content-encoding" property set to "gzip", MailerQ expects the message to be a gzip compressed JSON object instead. It first decompresses the message, then it parses the JSON. This means that you can publish both normal JSON encoded messages to RabbitMQ, as well as gzip compressed data. If you compress your input JSON, you do have to make sure that you also set the "content-encoding" header in the AMQP envelope that is published to RabbitMQ.

MailerQ not only consumes messages from RabbitMQ, it also publishes messages back to it, like the results that are sent to the result queues or the retries that are published back to the outbox queue. By default, MailerQ only sends pure JSON to RabbitMQ, without compressing it, even if you used compression yourself when you published the message to the outbox. If you want MailerQ to compress the data too, you can use a special setting in the config file.

rabbitmq-encoding:      gzip

The above setting only affects how MailerQ publishes messages to RabbitMQ. Messages consumed from RabbitMQ can still both be compressed or not, because MailerQ always inspects the "content-encoding" header from the AMQP envelope.

Quality of Service

When consuming from the outbox queue, or flushing a queue, MailerQ loads a certain number of messages at the same time, also called QoS. These numbers can be tweaked to lower memory usage.

rabbitmq-qos:         1000    (default: 1000)
rabbitmq-flush-qos:   1000    (default: 1000)
rabbitmq-minqos:      100     (default: 100)

This number is interpreted per consumer thread. Therefore, the maximum total number of messages from the outbox that are in memory at the same time is the amount of consumers multiplied by the maximum number of messages. For example, if "rabbitmq-consumers" is set to 5, and "rabbitmq-qos" is set to 200, the maximum total number of unacknowledged messages from the outbox queue is 1000.

The "rabbitmq-flush-qos" can be set to lower the loaded messages when a flush happens. Although MailerQ doesn't load in the messages, their bodies will be sent over TCP and so the TCP buffer may be fully populated with all this data. As this can happen for anything that is unpaused or resumes sending, a lot may be flushed at once.

"rabbitmq-minqos" is the lower bound for the QoS when MailerQ decides to scale back for performance reasons. The QoS will never go below this number, unless there aren't enought messages to reach it.

Throttle

To ensure messages are not lost, MailerQ uses publisher confirms by default. This makes sure that messages are not acknowledged before RabbitMQ has accepted responsibility for it. This will inherently tie it to the quality of service settings. However, to further tweak performance, a throttle can be set. This throttle makes sure that only a certain number of messages are actually sent over the socket. The advantage of this is that it reduces the load on RabbitMQ, and keeps the socket open to bidirectional communication. It used to be the case that MailerQ could not adequately respond to flow control by RabbitMQ, eventually causing TCP backpressure, shutting down communication.

rabbitmq-throttle:      100     (default: 100)