๐Ÿ RabbitMQ with Python

SOLID Principles, Clean Architecture & Best Practices

๐Ÿ“‹ Project Overview

๐Ÿ—๏ธ

SOLID Principles

Every component follows Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, and Dependency Inversion principles

๐Ÿ›๏ธ

Clean Architecture

Clear separation of concerns with Core, Infrastructure, Services, and Models layers

๐Ÿ”„

Event-Driven

Domain events with proper validation, routing, and error handling

๐Ÿ’‰

Dependency Injection

Proper DI container with service registry for testability and maintainability

๐Ÿ“Š

Monitoring

Health checks, metrics collection, and performance monitoring built-in

๐Ÿ›ก๏ธ

Error Handling

Comprehensive exception handling with retry logic and resilience patterns

๐Ÿ“ˆ Implementation Stats

15+
Classes
8
Interfaces
3
Services
6
Event Types
100%
Type Safe

๐Ÿ—๏ธ SOLID Principles Implementation

S

Single Responsibility

Each class has one reason to change

class UserService: # Only handles user domain logic
O

Open/Closed

Open for extension, closed for modification

class IEventHandler(ABC): # Easy to add new handlers
L

Liskov Substitution

Subtypes must be substitutable

publisher: IMessagePublisher # Any implementation works
I

Interface Segregation

Many specific interfaces vs one general

IMessagePublisher # Publishing IMessageConsumer # Consuming
D

Dependency Inversion

Depend on abstractions, not concretions

def __init__(self, publisher: IEventPublisher): self.publisher = publisher

๐ŸŽฌ SOLID in Action

IEventPublisher
โ†’
EventPublisher
โ†’
ProducerService

๐Ÿ›๏ธ Clean Architecture Layers

๐ŸŽฏ Core

Interfaces
Exceptions
Domain Logic

๐Ÿ“Š Models

Event DTOs
Validation
Factories

โš™๏ธ Services

User Service
Order Service
Payment Service

๐Ÿ”ง Infrastructure

RabbitMQ
Monitoring
Registry

๐Ÿ“œ Dependency Rules

โœ… Infrastructure โ†’ Services โ†’ Core
โŒ Core โ† Services โ† Infrastructure
โœ… All layers can use Models
โœ… Only Infrastructure knows RabbitMQ

โš™๏ธ Design Patterns

๐Ÿญ Factory Pattern

EventFactory creates validated events

EventFactory.create_event(EventType.USER_CREATED, **data)

๐Ÿ‘๏ธ Observer Pattern

Event handlers observe and react to domain events

registry.register_handler("user.created", handler)

๐Ÿ“ Registry Pattern

Service registry manages dependencies

registry.get_service("user_service")

๐ŸŽฏ Strategy Pattern

Different exchange types use different routing strategies

DirectExchange | FanoutExchange | TopicExchange

๐Ÿ“‹ Template Method

BaseEvent defines common structure

class UserCreatedEvent(BaseEvent):

๐Ÿ”Œ Adapter Pattern

RabbitMQ adapter implements messaging interfaces

class RabbitMQPublisher(IMessagePublisher):

๐Ÿ”„ Message Flow Animation

๐Ÿ“ค
Producer
โ†“
Event
โ†“
๐Ÿ”„
Publisher
โ†“
Routing Key
โ†“
๐Ÿ“‹
RabbitMQ
โ†“
Distributing...
โ†™
โ†“
โ†˜
๐Ÿ‘ค
User
๐Ÿ“ฆ
Order
๐Ÿ’ณ
Payment

๐Ÿ“ Flow Details

๐Ÿ’ป Code Examples

๐Ÿ”Œ Core Interfaces

class IEventPublisher(ABC):
    """Interface for publishing domain events"""

    @abstractmethod
    async def publish_event(
        self,
        event_type: str,
        event_data: Dict[str, Any],
        correlation_id: Optional[str] = None
    ) -> None:
        pass

class IEventHandler(ABC):
    """Interface for handling domain events"""

    @abstractmethod
    async def handle(
        self,
        event_data: Dict[str, Any],
        metadata: MessageMetadata
    ) -> None:
        pass

    @abstractmethod
    def can_handle(self, routing_key: str) -> bool:
        pass

โš™๏ธ Service Implementation

class UserEventHandler(IEventHandler):
    """Handles user-related events following SRP"""

    def can_handle(self, routing_key: str) -> bool:
        return routing_key in ["user.created", "user.updated"]

    async def handle(self, event_data: Dict[str, Any], metadata: MessageMetadata):
        event_type = event_data.get("event_type")

        if event_type == "user.created":
            await self._handle_user_created(event_data, metadata)
        elif event_type == "user.updated":
            await self._handle_user_updated(event_data, metadata)

    async def _handle_user_created(self, event_data, metadata):
        # Business logic for user creation
        event = UserCreatedEvent(**event_data)
        await self._create_user_profile(event)
        await self._send_welcome_email(event)

๐Ÿ“Š Event Models

class UserCreatedEvent(BaseEvent):
    """User creation event with validation"""

    event_type: str = Field(default="user.created", const=True)
    user_id: str
    email: str
    first_name: str
    last_name: str
    registration_source: Optional[str] = "web"

    @validator("email")
    def validate_email(cls, v):
        if "@" not in v:
            raise ValueError("Invalid email format")
        return v.lower()

class EventFactory:
    """Factory for creating validated events"""

    @classmethod
    def create_event(cls, event_type: EventType, **kwargs) -> BaseEvent:
        event_class = cls._event_mapping.get(event_type)
        if not event_class:
            raise ValueError(f"Unknown event type: {event_type}")
        return event_class(**kwargs)

๐ŸŽฏ Usage Examples

# Publishing events
await producer_service.user_registered(
    user_id="user123",
    email="john@example.com",
    first_name="John",
    last_name="Doe",
    correlation_id="req-456"
)

# Service setup with DI
connection_manager = RabbitMQConnectionManager(settings)
publisher = RabbitMQPublisher(connection_manager)
event_publisher = EventPublisher(publisher)
producer_service = ProducerService(event_publisher)

# Register handlers
registry.register_handler("user.created", user_handler)
registry.register_handler("order.placed", order_handler)

# Health monitoring
health = await health_monitor.check_system_health()
print(f"System status: {health.status}")