, have labored with machine studying or large-scale information pipelines, chances are high you’ve used some kind of queueing system.
Queues let companies speak to one another asynchronously: you ship off work, don’t wait round, and let one other system choose it up when prepared. That is important when your duties aren’t on the spot — suppose long-running mannequin coaching jobs, batch ETL pipelines, and even processing requests for LLMs that take minutes per question.
So why am I scripting this? I just lately migrated a manufacturing queueing setup to RabbitMQ, ran right into a bunch of bugs, and located that documentation was skinny on the trickier elements. After a good bit of trial and error, I assumed it’d be price sharing what I realized.
Hope you will see that this handy!
A fast primer: queues vs request-response mannequin
Microservices sometimes talk in two types — the traditional request–response mannequin, or the extra versatile queue-based mannequin.
Think about ordering pizza. In a request–response mannequin, you inform the waiter your order after which wait. He disappears, and thirty minutes later your pizza exhibits up — however you’ve been left at the hours of darkness the entire time.
In a queue-based mannequin, the waiter repeats your order, provides you a quantity, and drops it into the kitchen’s queue. Now it’s being dealt with, and also you’re free to do one thing else until the chef will get to it.
That’s the distinction: request–response retains you blocked till the work is finished, whereas queues affirm straight away and let the work occur within the background.
What’s Rabbit MQ?
RabbitMQ is a well-liked open-source message dealer that ensures messages are reliably delivered from producers (senders) to shoppers (receivers). First launched in 2007 and written in Erlang, it implements AMQP (Superior Message Queuing Protocol), an open customary for structuring, routing, and acknowledging messages.
Consider it like a put up workplace for distributed techniques: purposes drop off messages, RabbitMQ types them into queues, and shoppers choose them up when prepared.
A typical pairing within the Python world is Celery + RabbitMQ: RabbitMQ brokers the duties, whereas Celery staff execute them within the background.
In containerised setups, RabbitMQ sometimes runs in its personal container, whereas Celery staff run in separate containers that you would be able to scale independently.
The way it works at a excessive stage
Your app desires to run some work asynchronously. Since this process would possibly take some time, you don’t need the app to take a seat idle ready. As a substitute, it creates a message describing the duty and sends it to RabbitMQ.
- Change: This lives inside RabbitMQ. It doesn’t retailer messages however simply decides the place every message ought to go based mostly on guidelines you set (routing keys and bindings).
Producers publish messages to an change, which acts as a routing middleman. - Queues: They’re like mailboxes. As soon as the change decides which queue(s) a message ought to go to, it sits there until it’s picked up.
- Shopper: The service that reads and processes messages from a queue. In a Celery setup, the Celery employee is the patron — it pulls duties off the queue and does the precise work.
As soon as the message is routed right into a queue, the RabbitMQ dealer pushes it out to a shopper (if one is offered) over a TCP connection.
Core parts in Rabbit MQ
1. Routing and binding keys
Routing and binding keys work collectively to determine the place a message finally ends up.
- A routing secret’s hooked up to a message by the producer.
- A binding secret’s the rule a queue declares when it connects (binds) to an change.
A binding defines the hyperlink between an change and a queue.
When a message is distributed, the change appears on the message’s routing key. If that routing key matches the binding key of a queue, the message is delivered to that queue.
A message can solely have one routing key.
A queue can have one or a number of binding keys, that means it will possibly hear for a number of totally different routing keys or patterns.
2. Exchanges
An change in RabbitMQ is sort of a site visitors controller. It receives messages, doesn’t retailer messages, and it’s key job is to determine which queue(s) the message ought to go to, based mostly on guidelines.
If the routing key of a message doesn’t match any the binding keys of any queues, it is not going to get delivered.
There are a number of forms of exchanges, every with its personal routing type.
2a) Direct change
Consider a direct change like an actual deal with supply. The change appears for queues with binding keys that precisely match the routing key.
- If just one queue matches, the message will solely be despatched there (1:1).
- If a number of queues have the identical binding key, the message might be copied to all of them (1:many).
2b) Fanout change
A fanout change is like shouting by way of a loudspeaker.
Each message is copied to all queues certain to the change. The routing keys are ignored, and it’s all the time a 1:many broadcast.
Fanout exchanges might be helpful when the identical message must be despatched to a number of queues with shoppers who could course of the identical message in numerous methods.
2c) Subject change
A subject change works like a subscription system with classes.
Each message has a routing key, for instance "order.accomplished”. Queues can then subscribe to patterns corresponding to "order.*”. Because of this each time a message is expounded to an order, will probably be delivered to any queues which have subscribed to that class.
Relying on the patterns, a message would possibly find yourself in only one queue or in a number of on the identical time.
There are two necessary particular circumstances for binding keys:
*(star) matches precisely one phrase within the routing key.#(hash) matches zero or extra phrases.
Let’s illustrate this to make the syntax alot extra intuitive.

second) Headers change
A headers change is like sorting mail by labels as an alternative of addresses.
As a substitute of wanting on the routing key (like "order.accomplished"), the change inspects the headers of a message: These are key–worth pairs hooked up as metadata. As an example:
x-match: all, precedence: excessive, kind: electronic mail→ the queue will solely get messages which have eachprecedence=excessiveandkind=electronic mail.x-match: any, area: us, area: eu→ the queue will get messages the place no less than one of the circumstances is true (area=usorarea=eu).
The x-match subject is what determines whether or not all guidelines should match or anybody rule is sufficient.
As a result of a number of queues can every declare their very own header guidelines, a single message would possibly find yourself in only one queue (1:1) or in a number of queues without delay (1:many).
Headers exchanges are much less frequent in apply, however they’re helpful when routing relies on extra advanced enterprise logic. For instance, you would possibly need to ship a message provided that customer_tier=premium, message_format=json, or area=apac .
2e) Lifeless letter change
A useless letter change is a security web for undeliverable messages.
3. A push supply mannequin
Because of this as quickly as a message enters a queue, the dealer will push it out to a shopper that’s subscribed and prepared. The shopper doesn’t request messages and as an alternative simply listens on the queue.
This push strategy is nice for low-latency supply — messages get to shoppers as quickly as potential.
Helpful options in Rabbit MQ
Rabbit MQ’s structure enables you to form message movement to suit your workload. Listed here are some helpful patterns.
Work queues — competing shoppers sample
You publish duties into one queue, and many shoppers (eg. celery staff) all hearken to that queue. The dealer delivers every message to precisely one shopper, so staff “compete” for work. This implicitly interprets to easy load-balancing.
Should you’re on celery, you’ll need to preserve worker_prefetch_multiplier=1 . What this implies is {that a} employee will solely fetch one message at a time, avoiding sluggish staff from hoarding duties.
Pub/sub sample
A number of queues certain to an change and every queue will get a copy of the message (fanout or matter exchanges). Since every queue will get its personal message copy, so totally different shoppers can course of the identical occasion in numerous methods.
Specific acknowledgements
RabbitMQ makes use of express acknowledgements (ACKs) to ensure dependable supply. An ACK is a affirmation despatched from the patron again to the dealer as soon as a message has been efficiently processed.
When a shopper sends an ACK, the dealer removes that message from the queue. If the patron NACKs or dies earlier than ACKing, RabbitMQ can redeliver (requeue) the message or route it to a useless letter queue for inspection or retry.
There may be, nevertheless, an necessary nuance when utilizing Celery. Celery does ship acknowledgements by default, however it sends them early — proper after a employee receives the duty, earlier than it truly executes it. This behaviour (acks_late=False, which is the default) implies that if a employee crashes halfway by way of operating the duty, the dealer has already been advised the message was dealt with and gained’t redeliver it.
Precedence queues
RabbitMQ has a out of the field precedence queueing function which lets larger precedence messages soar the road. Underneath the hood, the dealer creates an inside sub-queue for every precedence stage outlined on a queue.
For instance, when you configure 5 precedence ranges, RabbitMQ maintains 5 inside sub-queues. Inside every stage, messages are nonetheless consumed in FIFO order, however when shoppers are prepared, RabbitMQ will all the time attempt to ship messages from higher-priority sub-queues first.
Doing so implicitly would imply an growing quantity of overhead if there have been many precedence ranges. Rabbit MQ’s docs note that though priorities between 1 and 255 are supported, values between 1 and 5 are highly recommended.
Message TTL & scheduled deliveries
Message TTL (per-message or per-queue) routinely expires stale messages; and delayed supply is offered through plugins (e.g., delayed-message change) while you want scheduled execution.
The way to optimise your Rabbit MQ and Celery setup
While you deploy Celery with RabbitMQ, you’ll discover a couple of “thriller” queues and exchanges showing within the RabbitMQ administration dashboard. These aren’t errors — they’re a part of Celery’s internals.
After a couple of painful rounds of trial and error, right here’s what I realized about how Celery actually makes use of RabbitMQ underneath the hood — and easy methods to tune it correctly.
Kombu
Celery depends on Kombu, a Python messaging framework. Kombu abstracts away the low-level AMQP operations, giving Celery a high-level API to:
- Declare queues and exchanges
- Publish messages (duties)
- Eat messages in staff
It additionally handles serialisation (JSON, Pickle, YAML, or customized codecs) so duties might be encoded and decoded throughout the wire.
Celery occasions and the celeryev Change

Celery contains an occasion system that tracks employee and process state. Internally, occasions are revealed to a particular matter change referred to as celeryev.
There are two such occasion varieties:
- Employee occasions eg.
employee.on-line,employee.heartbeat,employee.offlineare all the time on and are light-weight liveliness alerts. - Job occasions, eg.
task-received,task-started,task-succeeded,task-failedthat are disabled by default except the-Eflag is added.
You have got fantastic grain management over each forms of occasions. You may flip off employee occasions (by turning off gossip, extra on that beneath) whereas turning on process occasions.
Gossip
Gossip is Celery’s mechanism for staff to “chat” about cluster state — who’s alive, who simply joined, who dropped out, and sometimes elect a pacesetter for coordination. It’s helpful for debugging or ad-hoc cluster coordination.
By default, Gossip is enabled. When a employee begins:
- It creates an unique, auto-delete queue only for itself.
- That queue is certain to the
celeryevmatter change with the routing key sampleemployee.#.
As a result of each employee subscribes to each employee.* occasion, the site visitors grows rapidly because the cluster scales.
With N staff, every one publishes its personal heartbeat, and RabbitMQ followers that message out to the opposite N-1 gossip queues. In impact, you get an N × (N-1) fan-out sample.
In my setup with 100 staff, that meant a single heartbeat was duplicated 99 occasions. Throughout deployments — when staff had been spinning up and shutting down, producing a burst of be part of, depart, and heartbeat occasions — the sample spiraled uncontrolled. The celeryev change was out of the blue dealing with 7–8k messages per second, pushing RabbitMQ previous its reminiscence watermark and leaving the cluster in a degraded state.
When this reminiscence restrict is exceeded, RabbitMQ blocks publishers till utilization drops. As soon as reminiscence falls again underneath the edge, RabbitMQ resumes regular operation.
Nevertheless, which means through the reminiscence spike the dealer turns into unusable — successfully inflicting downtime. You gained’t need that in manufacturing!
The answer is to disable Gossip so staff don’t bind to employee.#. You are able to do this within the docker compose the place the employees are spun up.
celery -A myapp employee --without-gossip
Mingle
Mingle is a employee startup step the place the brand new employee contacts different staff to synchronise state — issues like revoked duties and logical clocks. This occurs solely as soon as, throughout employee boot. Should you don’t want this coordination, you can even disable it with --without-mingle
Occasional connection drops
In manufacturing, connections between Celery and RabbitMQ can sometimes drop — for instance, as a consequence of a short community blip. If in case you have monitoring in place, you might even see these as transient errors.
The excellent news is that these drops are often recoverable. Celery depends on Kombu, which incorporates computerized connection retry logic. When a connection fails, the employee will try to reconnect and resume consuming duties.
So long as your queues are configured appropriately, messages are not misplaced:
sturdy=True(queue survives dealer restart)delivery_mode=2(persistent messages)- Shoppers ship express ACKs to verify profitable processing
If a connection drops earlier than a process is acknowledged, RabbitMQ will safely requeue it for supply as soon as the employee reconnects.
As soon as the connection is re-established, the employee continues regular operation. In apply, occasional drops are fantastic, so long as they continue to be rare and queue depth doesn’t construct up.
To finish off
That’s all people, these are a few of the key classes I’ve realized operating RabbitMQ + Celery in manufacturing. I hope this deep dive has helped you higher perceive how issues work underneath the hood. If in case you have extra ideas, I’d love to listen to them within the feedback and do attain out!!

