Dhanman Microservices Messaging Architecture¶
Overview¶
Dhanman uses RabbitMQ as the primary message broker to enable asynchronous, event-driven communication between microservices. The messaging infrastructure is built on top of B2aTech.CrossCuttingConcern library with patterns inspired by MassTransit for reliable, scalable inter-service communication.
This architecture enables: - Loose coupling between services - Asynchronous processing for better responsiveness - Event-driven workflows across bounded contexts - Scalability through distributed message processing - Resilience with automatic retries and dead-letter handling
1. Messaging Architecture Overview¶
Key Concepts¶
Exchange¶
The entry point for messages in RabbitMQ. Routes messages to queues based on exchange type and routing keys.
Exchange Types: - Fanout: Broadcasts messages to all bound queues (used for events) - Direct: Routes to specific queues based on routing keys (used for commands) - Topic: Routes based on routing key patterns (future use) - Headers: Routes based on message headers (not currently used)
Queue¶
Holds messages until consumed by a service. Each microservice has dedicated queues for commands and events.
Queue Properties: - Durable: Survives broker restarts - Auto-delete: Removed when no consumers - Exclusive: Used by single connection only - TTL: Time-to-live for messages
Routing Key¶
String used by exchanges to determine message routing. Format: {service}.{message-type}.{action}
Examples:
- sales.command.create-invoice
- sales.event.invoice-created
- common.command.send-notification
Publisher¶
Service that sends messages to exchanges. Uses IEventPublisher or ICommandPublisher interfaces.
Consumer¶
Service that receives and processes messages from queues. Implements IMessageHandler<T> interface.
MassTransit-Inspired Patterns¶
While Dhanman uses a custom implementation built on RabbitMQ.Client, it adopts proven patterns from MassTransit:
- Message Conventions: Clear separation of commands, events, and queries
- Retry Policies: Exponential backoff for transient failures
- Circuit Breaker: Prevent cascade failures
- Outbox Pattern: Ensure exactly-once delivery
- Saga Pattern: Long-running distributed transactions
- Consumer Configuration: Concurrent message processing with prefetch limits
2. Our Exchanges¶
We have two main exchanges configured:
| Exchange Name | Type | Purpose |
|---|---|---|
| dhanman.events | Fanout | Broadcast event messages to all subscribed queues |
| dhanman.commands | Direct | Route commands to specific service queues based on routing keys |
3. Queues¶
Each microservice has dedicated queues to consume commands and events:
| Microservice | Command Queue | Event Queue |
|---|---|---|
| Sales | sales.commands | sales.events |
| Purchase | purchase.commands | purchase.events |
| Common | common.commands | common.events |
| Community | community.commands | community.events |
| Payroll | payroll.commands | payroll.events |
| Inventory | inventory.commands | inventory.events |
4. Types of Messages¶
-
Events:
Represent something that has happened (e.g.,UserCreatedEvent,InvoiceCreatedEvent). Published typically with fanout exchange to notify all interested services. -
Commands:
Represent instructions for something to be done (e.g.,CreateInvoiceCommand). Routed with direct exchange using routing keys targeting specific service queues.
5. Publishers & Consumers¶
Publishers¶
-
IEventPublisher(in B2aTech.CrossCuttingConcern):
Publishes events todhanman.eventsfanout exchange using contracts from Dhanman.Shared.Contracts. -
ICommandPublisher(in B2aTech.CrossCuttingConcern):
Publishes commands todhanman.commandsdirect exchange with routing keys.
Consumers¶
-
IEventConsumer(in B2aTech.CrossCuttingConcern):
Consumes from event queues subscribed to the fanout exchange. -
ICommandConsumer(in B2aTech.CrossCuttingConcern):
Consumes from command queues directly routed by the command exchange.
6. Common Service Role¶
The Common microservice primarily consumes events like:
InvoiceCreatedEventPaymentMadeEventPaymentReceivedEventBillCreatedEventSalaryPostedEventSalaryCreatedEvent
which originate in Sales, Purchase, Payroll, etc. Common processes these to update ledger entries and maintain core accounting records.
7. What Has Been Done¶
- RabbitMQ instances deployed with Docker for QA and Production.
- Exchanges and queues declared programmatically at startup for idempotency.
- Messaging infrastructure abstracted in B2aTech.CrossCuttingConcern reusable package.
- Shared contracts for events and commands defined in Dhanman.Shared.Contracts.
- Each microservice (Sales, Purchase, Common, etc.) has a background hosted service that listens to its respective queues.
- Basic event and command handlers implemented (e.g.,
UserCreatedEventHandler). - Dependency injection and service registration set up for messaging components.
8. Developer Responsibilities Going Forward¶
Defining New Events/Commands¶
- Add DTOs to Dhanman.Shared.Contracts for new messages.
Publishing Messages¶
- Use
IEventPublisherorICommandPublisherin your microservice (e.g., Sales) to publish messages upon domain events or actions.
Consuming Messages¶
- Implement
IMessageHandler<T>for relevant events/commands in consuming microservices (e.g., Common listens to Sales events).
Queue & Exchange Management¶
- Declare any new queues or bindings in
RabbitMqInitializeror ensure they are declared via consumers’ startup code.
Hosted Service Registration¶
- Register
RabbitMqListenerHostedServicein your microservice’sProgram.csto start consuming messages.
Handle Idempotency¶
- Make your handlers resilient to repeated or duplicate messages.
9. Useful RabbitMQ Management Tips¶
- Use the RabbitMQ Management UI (rabbitmq.dhanman.com) to monitor queues, exchanges, message rates.
- View ready/unacknowledged message counts to monitor health.
- Inspect logs and dead-letter queues for errors.
Summary¶
This messaging architecture, built on B2aTech.CrossCuttingConcern and Dhanman.Shared.Contracts, establishes a consistent, scalable foundation for inter-service communication across the Dhanman ecosystem. Developers extending any microservice should align with these patterns to ensure reliability and maintainability.
Architecture Diagram¶
