Dead Letter Queue Failed Messages List Mock in Python
Implements a simple in-memory dead letter queue to collect, list, and retry failed messages, with JSON serialization for inspection in streaming pipelines.
Python code
52 linesimport json
from collections import deque
class Message:
def __init__(self, message_id, payload, attempts=0):
self.message_id = message_id
self.payload = payload
self.attempts = attempts
def __repr__(self):
return f"Message(id={self.message_id}, attempts={self.attempts})"
class DeadLetterQueue:
def __init__(self):
self.failed_messages = deque()
def add_failed(self, message):
self.failed_messages.append(message)
def list_failed(self):
return list(self.failed_messages)
def retry(self, message_id):
for i, msg in enumerate(self.failed_messages):
if msg.message_id == message_id:
msg.attempts += 1
self.failed_messages[i] = msg
return msg
return None
if __name__ == "__main__":
dlq = DeadLetterQueue()
dlq.add_failed(Message("msg-001", {"data": "first failure"}))
dlq.add_failed(Message("msg-002", {"data": "second failure"}))
dlq.add_failed(Message("msg-003", {"data": "third failure"}))
print("Failed messages:")
for msg in dlq.list_failed():
print(f" {msg.message_id}, attempts={msg.attempts}")
dlq.retry("msg-001")
print("\nAfter retry of msg-001:")
for msg in dlq.list_failed():
print(f" {msg.message_id}, attempts={msg.attempts}")
print("\nJSON representation:")
payloads = [{"message_id": m.message_id, "payload": m.payload, "attempts": m.attempts}
for m in dlq.list_failed()]
print(json.dumps(payloads, indent=2))
Output
Failed messages:
msg-001, attempts=0
msg-002, attempts=0
msg-003, attempts=0
After retry of msg-001:
msg-001, attempts=1
msg-002, attempts=0
msg-003, attempts=0
JSON representation:
[
{
"message_id": "msg-001",
"payload": {
"data": "first failure"
},
"attempts": 1
},
{
"message_id": "msg-002",
"payload": {
"data": "second failure"
},
"attempts": 0
},
{
"message_id": "msg-003",
"payload": {
"data": "third failure"
},
"attempts": 0
}
]
How it works
The DeadLetterQueue uses a deque to store failed messages, providing O(1) append operations and efficient iteration. The add_failed method appends a message, while list_failed returns a list snapshot for inspection. The retry method locates a message by ID, increments its attempt counter, and updates it in place, simulating a retry without losing the message. JSON serialization is done with json.dumps, converting each message to a dictionary for easy logging or external inspection. This lightweight pattern models how production DLQs store and expose failed messages for debugging and reprocessing.
Common mistakes
- Using a list instead of deque, which can be slower for frequent appends and pops
- Modifying the deque while iterating, which can cause runtime errors or missed items
- Assuming retry removes the message from the queue, but the code just increments attempts
- Not serializing the payload correctly when it contains non-JSON-serializable objects
Variations
- Use a dict keyed by message_id for O(1) lookups instead of scanning the deque
- Add a max-retry threshold to automatically move messages to a permanent DLQ after N attempts
Real-world use cases
- Collecting failed Kafka or RabbitMQ messages for manual inspection in a monitoring dashboard.
- Providing a retry mechanism for failed webhook deliveries before alerting an incident response team.
- Maintaining an audit trail of processing failures in an ETL job for later reprocessing.
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
- Dedupe processed message IDs in Python easy
- Event Envelope with Schema Version Field in Python easy
- Event sourcing append store replay in Python easy
Keep learning
Related tutorials and quizzes for this topic.