Modular Monolith → Event-Driven Services
Very HighDecomposing a modular monolith into independently deployed services communicating over an event stream, introducing async processing boundaries and eventual consistency in exchange for independent deployability and fault isolation.
Topology Changes
From
Modular Monolith
To
Event-Driven Services
Topology Mutations
Event stream introduced as the communication backbone between services
Operational Impact
New operational surface: consumer lag, broker availability, partition assignment, offset management
Order completion previously called notification module synchronously: now emits an OrderCompleted event
Operational Impact
Notification failures no longer cause order transaction rollback; notification may lag seconds behind order commit
Each service becomes independently deployable with its own build pipeline
Operational Impact
API contract versioning required; consumers must tolerate schema evolution
Shared database transactions replaced by event-driven compensating transactions (Saga pattern)
Operational Impact
Partial failure states become observable: compensating logic required for every multi-service workflow
Correlation IDs and trace propagation required to follow requests across service boundaries
Operational Impact
Without tracing, production debugging of cross-service failures is nearly impossible
Shared monolith database split into per-service schemas or separate database instances
Operational Impact
Cross-service queries must become API calls or event-driven projections: joins are no longer possible
Migration Stages
Add a routing layer in front of the monolith. All traffic still hits the monolith. Instrument all inter-module calls so volume and latency are visible before splitting.
Deploy message broker (Kafka or RabbitMQ). Establish topic naming conventions, serialization format (Avro/JSON), and consumer group conventions. Set up consumer lag monitoring before any service uses the broker.
The monolith begins emitting events for key domain events while still performing synchronous operations. New services consume events but do not yet replace monolith logic. Both paths coexist.
Extract the lowest-dependency module first (typically notifications, search indexing, or analytics). This service receives events and has no outbound calls to the monolith. Validate event schema, consumer lag behavior, and monitoring.
Migrate extracted service to its own database. This is the highest-risk step. Requires dual-read period, data migration validation, and cutover coordination.
Repeat extraction for remaining modules in order of ascending dependency complexity. Each extraction validates event contracts, observability, and failure handling.
Migration Risks
Cross-service workflows that previously used database transactions now require Saga orchestration
Mitigation
Design idempotent event handlers; implement compensating transactions for every multi-step workflow; test failure injection in staging
Consumer lag silently accumulates: a lagging consumer is not a failed consumer
Mitigation
Alert on consumer lag rate-of-change, not absolute depth; implement dead letter queues with alerting
Database decomposition is irreversible: a failed cutover may require emergency data reconciliation
Mitigation
Maintain dual-read period of at least 2 weeks; validate row counts and checksums before cutting over
Shared event schema creates implicit coupling: schema changes break all consumers
Mitigation
Use a schema registry (Confluent Schema Registry or Avro); enforce backward-compatible schema evolution
Distributed tracing adoption is frequently deferred until debugging becomes impossible
Mitigation
Require distributed tracing as a precondition for any service extraction; no service ships without trace propagation
Coupling Changes
Services must coordinate schema evolution, consumer lag, and deployment ordering
Consequence
Schema registry, consumer lag alerts, and contract tests become mandatory operational infrastructure
Per-service databases prevent cross-service schema coupling
Consequence
Cross-service reporting requires event-driven projections or analytical exports: no direct joins
Services deploy independently
Consequence
API versioning and consumer backward compatibility become permanent engineering responsibilities
Cross-service workflows require explicit compensating transaction logic
Consequence
Every multi-service operation must have a documented rollback path or be designed idempotent
Consistency Model Changes
- ·Intra-service operations remain strongly consistent (per-service ACID database)
- ·Cross-service operations become eventually consistent: consumer lag determines the window
- ·Saga-based compensating transactions replace distributed transactions: partial failure states are observable
- ·Read-after-write consistency violations become possible when reading from a different service
Rollback Risks
- ·Database decomposition is irreversible: data has been migrated to a separate database instance
- ·Event-sourced services may have months of event history that cannot be mapped back to the monolith schema
- ·Consumer groups that have committed offsets cannot be trivially rolled back to monolith reads
- ·API contract changes made by extracted services may have already been consumed by clients