Using negation in the RabbitMQ routing key or header's attributes

Viewed 655

I have a situation when I need to create a route for my messages but I would like to use a matching pattern with negation, like !myPattern.

Example:

I have a queue bound in a Topic Exchange and the routing key is #.brazil.#. So it means that this queue will only receive messages when in the message's routing key contains ".brazil." like message.brazil.denmark.

Now I want to create another queue and bind to the same Topic Exchange but I want to receive all messages that don't contain the pattern #.brazil.#, something like !(#.brazil.#).

I was making some tests using Headers Exchange but the x-match argument only can have 2 possible values: any and all, and I need something like except.

1 Answers

Basically it is not possible to use negation in RabbitMQ even in routing key or header's attribute.

As far as I found out, there are 3 options here:

1 - Using an alternate exchange feature

Declare a fanout exchange you'll publish to (let's call it "my-exchange").

Declare a fanout exchange called "junk".

When each consumer declares a queue, it also declares a topic exchange 
and a fanout exchange. 

The alternate-exchange for the topic exchange should be set to the fanout exchange. 

It then binds the topic exchange to "my-exchange", and "junk" to the topic 
exchange, with a routing key equal to the topics it doesn't want.

Thus messages with the "bad" routing key go:

   [my-exchange] -> [per-consumer-topic] -> [junk]

and the rest go:

   [my-exchange] -> [per-consumer-topic] -> [per-consumer-fanout] ->
[per-consumer-queue]

Solution By: Simon MacMullen-2

Thread Reference: http://rabbitmq.1065348.n5.nabble.com/Binding-to-topic-exchange-with-a-negation-wildcard-td21964.html

2 - Using a Router Consumer

On this solution, you will have only 1 consumer bound in your queue, and the 
unique responsibility of this consumer will be "redirect" the message to other 
exchanges based on your rules. 

Now your router logic will be centralized on this "orchestrator" and not in 
RabbitMQ anymore (routing keys or header's attr).

3 - Using a Fanout Exchange

This solution is simple but has a huge drawback, scaling.

Basically you will have a Fanout Exchange responsible to deliver the message to all bound queues and all consumers will receive the message and check if it should process or discard the message, it means that now the "router logic" will be on the consumer side.

The problem with this solution is if you want to scale a specific consumer and your process is not idempotent you will process the message more than 1 time (the number of instances running of your consumer).

So in my case, the best approach was the Router Consumer.

Related