How to Mock RabbitMQ Ack Nack Requeue in Python
A mock RabbitMQ channel and consumer that simulates ack, nack, and requeue handling for testing message processing logic without a broker.
Python code
52 linesimport json
from collections import deque
class MockChannel:
def __init__(self):
self.acked = []
self.nacked = []
self.requeued = []
def basic_ack(self, delivery_tag):
self.acked.append(delivery_tag)
def basic_nack(self, delivery_tag, requeue=False):
self.nacked.append({"tag": delivery_tag, "requeue": requeue})
if requeue:
self.requeued.append(delivery_tag)
class MockConsumer:
def __init__(self, messages):
self.channel = MockChannel()
self.message_queue = deque(messages)
self.delivery_tag_counter = 0
def process_next(self):
if not self.message_queue:
return None
message = self.message_queue.popleft()
self.delivery_tag_counter += 1
tag = self.delivery_tag_counter
payload = json.loads(message)
if payload.get("valid"):
self.channel.basic_ack(tag)
else:
self.channel.basic_nack(tag, requeue=True)
return payload
if __name__ == "__main__":
messages = [
'{"id": 1, "valid": true}',
'{"id": 2, "valid": false}',
'{"id": 3, "valid": true}',
]
consumer = MockConsumer(messages)
while consumer.process_next() is not None:
pass
print("Acked:", consumer.channel.acked)
print("Nacked:", consumer.channel.nacked)
print("Requeued:", consumer.channel.requeued)
Output
Acked: [1, 3]
Nacked: [{'tag': 2, 'requeue': True}]
Requeued: [2]
How it works
The MockChannel captures ack and nack calls with delivery tags, recording requeued tags separately. Each message gets a sequential tag as it's pulled from a deque. The consumer parses JSON and checks the valid field: true messages are acked, false messages are nacked with requeue=True. The main loop drains all messages, and the channel's history is printed to verify behavior.
Common mistakes
- Forgetting to simulate delivery tag increments per message
- Not distinguishing between nack with and without requeue when recording state
- Overlooking that deque.popleft is O(1) but list.pop(0) is O(n)
Variations
- Use unittest.mock.MagicMock for a lighter, less structured mock
- Add an explicit sleep or callback to simulate async processing
Real-world use cases
- Unit-testing consumer logic that must ack successful messages and requeue dead-letter candidates.
- Simulating broker behavior for integration tests of a queue-processing service without Docker.
- Validating retry policies and poison-message handling in a background job runner.
Sponsored
More from Streaming & messaging
- At Most Once Fire-and-Forget Mock in Python easy
- Batch Consume Process Commit Pattern in Python medium
- Build a Streaming Messaging Helper in Python easy
- Dead Letter Queue Failed Messages List Mock in Python easy
- Dedupe processed message IDs in Python easy
- Event Envelope with Schema Version Field in Python easy
Keep learning
Related tutorials and quizzes for this topic.