ADR-0003: Event-Driven Architecture Implementation¶
Status¶
PROPOSED
Date: 2025-07-05
Changelog¶
| Date | Revision | Description | Author |
|---|---|---|---|
| 2025-07-05 | 1.0 | Initial version | souperk |
Context¶
As the Loryth project evolves with multiple services (budget, cms, issues, journal), we need an efficient communication pattern between these services. The traditional request-response pattern has limitations in terms of scalability, resilience, and loose coupling.
Key factors influencing this decision: - Need for asynchronous communication between services - Requirement for resilience when services are temporarily unavailable - Desire for loose coupling between services - Need for scalability as the system grows - Need for reliable message delivery, including retry mechanisms - Performance considerations for batch operations
Decision¶
We will implement an event-driven architecture for inter-service communication with the following key components:
-
Message Broker System: We will use a reliable message broker (e.g., RabbitMQ or Kafka) to handle event distribution between services.
-
Event Publishing:
- Services will publish domain events when significant state changes occur
- Batch publishing capability will be implemented for high-volume operations
-
Events will follow a standardized format with metadata, timestamp, and payload
-
Event Consumption:
- Services will subscribe to relevant events from other services
- Idempotent message processing to handle potential duplicates
-
Retry mechanisms with exponential backoff for failed message processing
-
Message Schema:
- Versioned event schemas to allow for backward compatibility
-
Schema registry to manage and validate event formats
-
Error Handling:
- Dead letter queues for messages that fail processing
- Monitoring and alerting for message processing failures
- Circuit breakers to prevent cascade failures
Consequences¶
Positive¶
- Loose Coupling: Services can evolve independently as long as they maintain compatible event interfaces
- Scalability: Services can scale independently based on their processing needs
- Resilience: Services can continue to function when other services are temporarily unavailable
- Flexibility: New services can be added to consume existing events without modifying publishers
- Reliability: Retry mechanisms ensure reliable message delivery even in failure scenarios
Negative¶
- Increased Complexity: Event-driven systems introduce additional complexity in terms of debugging and monitoring
- Eventually Consistent: System will be eventually consistent rather than immediately consistent
- Learning Curve: Team will need to adapt to event-driven thinking and patterns
- Infrastructure Overhead: Additional infrastructure components (message broker, monitoring) required
Neutral¶
- Message Versioning: Will require careful management of message schema versions as the system evolves
- Observability: Additional tooling needed for tracing event flows through the system
- Testing: Different testing approaches needed for asynchronous event-based interactions
Alternatives Considered¶
- Synchronous API Calls
- Description: Direct REST/gRPC calls between services
- Pros:
- Simpler implementation and debugging
- Immediate consistency
- More familiar pattern for developers
- Cons:
- Tight coupling between services
- Reduced resilience to failures
- Potential for cascading failures
- Increased latency for user operations
-
Why not chosen: Does not provide the resilience and loose coupling needed for our distributed architecture
-
Hybrid Approach
- Description: Use synchronous calls for critical paths and events for non-critical operations
- Pros:
- Balance between consistency and resilience
- Optimized for different types of operations
- Cons:
- Increased complexity with two communication patterns
- Potential inconsistency in how features are implemented
- Why not chosen: Added complexity without clear boundaries between approaches would lead to confusion