Microservices and Event Sourcing in Ruby
Message-based services hosted in any number of operating system processes or machines, with actor-based pub-sub consumers, component hosting, message dispatching, and handlers
Business logic entities projected from event streams with both in-memory, first-level caching and second-level on disk caching
Support for Postgres and EventStore message stores and transports, depending on your performance and scale needs
# Account command handler with withdrawal implementation # Business logic for processing a withdrawal class Handler include Messaging::Handle handle Withdraw do |withdraw| account_id = withdraw.account_id account = store.fetch(account_id) unless account.sufficient_funds?(withdraw.amount) logger.info('Withdrawal rejected') return end withdrawn = Withdrawn.follow(withdraw) time = clock.iso8601 withdrawn.processed_time = time stream_name = stream_name(account_id) write.(withdrawn, stream_name) end end # Withdraw command message # Send to the account component to effect a withdrawal class Withdraw include Messaging::Message attribute :account_id, String attribute :amount, Numeric attribute :time, String end # Withdrawn event message # Event is written by the handler when a withdrawal is successfully processed class Withdrawn include Messaging::Message attribute :account_id, String attribute :amount, Numeric attribute :time, String attribute :processed_time, String end # Account entity # The account component's model object class Account include Schema::DataStructure attribute :id, String attribute :balance, Numeric, default: 0 def withdraw(amount) self.balance -= amount end def sufficient_funds?(amount) balance >= amount end end # Account entity projection # Applies account events to an account entity class Projection include EntityProjection entity_name :account apply Withdrawn do |withdrawn| account.id = withdrawn.account_id amount = withdrawn.amount account.withdraw(amount) end end # Account entity store # Projects an account entity and keeps a cache of the result class Store include EntityStore entity Account projection Projection end
Note: This example code is abridged for brevity, and some elements necessary for it to be runnable are redacted. For more complete and representative example implementations, as well as the unabridged version of this example, see the examples section.