Internals
RailsEventStore (RES) is a set of Ruby gems designed for event sourcing in Rails and Ruby applications. It helps developers store domain events, publish them to subscribers, and build read models — all while embracing a CQRS (Command Query Responsibility Segregation) and Event Sourcing architecture.
Let’s break down the internal parts:
Core Components of RailsEventStore
Client
Acts as the main entry point for appending, publishing & subscribing to events.
Both RubyEventStore::Client
and RailsEventStore::Client
(inherited from the Ruby client)
allow you to set up the RES instance according to your project's needs.
It orchestrates the flow between application code and RES storage & pub/sub parts.
RailsEventStore::Client
provides client setup ready to use with Ruby on Rails,
featuring an ActiveRecord
-based event repository (storage) and asynchronous-ready dispatcher
based on ActiveJob
(pub/sub) . It also wraps internal components with instrumentation
provided by ActiveSupport::Notifications
. At the same time it allows you to configure each part
based on project's needs.
Storage
Manages the persistence and retrieval of events. As simple as it sounds, the implementation focuses on the efficient storage and retrieval of events from the database.
Each event stored must be mapped into SerializedRecord
object using provided mapper.
Read events (SerializedRecord
objects) are transformed into Ruby domain event classes
using the mapper component.
It can be replaced by your own implementation
(see contrib gems for ROM
& Sequel
event repository implementations).
Mapper
This component is responsible for transforming domain event (Ruby class) into SerializedRecord
- each to store & transmit form of event's data.
By default it is set up to use pipeline mapper with defined set of transformations.
It could be extended by defining new transformations (see RubyEventStore::Mappers::EncryptionMapper
as an example) or completely replaced by your own implementation. It needs to transform in both directions
between domain object class and SerializedRecord
object.
Pub/Sub broker
This component is responsible for delivering domain events to subscribers.
It manages the subscriptions for domain events, and dispatches published events to their destinations.
While RubyEventStore::Client
uses only simple synchronous dispatcher, the RailsEventStore::Client
has a
far more sophisticated setup.
The RailsEventStore::Client
default setup uses composed dispatchers, allowing several methods
of delivering events to subscribers. The defined dispatchers are processed in order,
and the first capable of handling delivery is used. This enables a mix of synchronous
and asynchronous delivery of domain events.
Asynchrounus delivery is handled by RailsEventStore::AfterCommitAsyncDispatcher
,
which ensures that domain events are scheduled in the asynchronous queue only after being stored in the database.
By default, it uses RailsEventStore::ActiveJobScheduler
to schedule processing via ActiveJob
, but
other solutions have also been implemented (like Sidekiq
using ruby_event_store-sidekiq_scheduler
gem).
Both RubyEventStore::Client
and RailsEventStore::Client
can be customized with your own dispatcher to suit your needs.
Typical usage
The diagrams below show (almost) all internal interactions between RES components for the most common operations.