Skip to content

How to implement an event driven architecture in Ruby on Rails (using Domain Driven Design principles)

Notifications You must be signed in to change notification settings

fast-programmer/message_driven_app

Repository files navigation

Event-Driven Architecture Demo with Ruby on Rails

This project illustrates how to build an event-driven architecture in Ruby on Rails, following many Doman Driven Design best practices including:

  1. layered architecture: HTTP, GraphQL, ruby console -> calls stateless application service -> orchestrates models
  2. modularised monolith: models exist in subdomains, and subdomains communicate with each other indirectly via model events
  3. aggregate consistency: lock version on all model aggregates protects against multithreading bugs

Benefits of Event-Driven Architecture (EDA)

  1. Simplicity: A shared, event-centric conceptual model provides a unified, non-technical understanding across different system components and stakeholders, reducing complexity and facilitating clearer communication.

  2. Visibility: By centralizing event logging it becomes easier to monitor, troubleshoot, and debug system issues.

  3. Scalability: EDA's are highly scalable. They can handle high volumes of events and adapt to changes in these volumes over time.

  4. Decoupling: EDA promotes loose coupling between system components, as each component only knows about the event and how to handle it. This allows developers to work on individual components without impacting the whole system.

  5. Resiliency: By separating the event producers from the consumers, the system becomes more resilient. If one part of the system fails, it won't directly affect the others.

Conceptual Model Example

Screenshot from 2023-06-14 08-56-18

Getting Started

Clone the repository and install the dependencies:

git clone https://github.com/fast-programmer/message_driven_app.git
cd message_driven_app
bundle install

After installing, you can create the database and run the migration:

RAILS_ENV=development bin/rake db:create
RAILS_ENV=development bin/rake db:migrate

How to create an unpublished model event (in band)

RAILS_ENV=development bin/rails c
User.create(email: '[email protected]')

# OR

ActiveRecord::Base.transaction do
  user = Models::User.create(email: '[email protected]')
  user.events.create!(name: 'User.create')
end
SELECT * FROM messages ORDER BY created_at ASC;

Screenshot from 2023-06-14 09-37-25

irb(main):005:0> Models::User.find(2).events.map { |event| event.name }
=> ["User.created"]

How to publish an unpublished model event (out of band)

bin/message_publisher

This script enumerates through all unpublished events, calling message handlers in each subdomain

  • if the handlers do not throw any exceptions, set the message status to published
  • if the handlers do throw an exception, set the message status to failed

How to react to a model event being published (out of band)

The publisher broadcasts each event to all subdomain message handlers.

Inside each subdomain message handler, messages are routed to handlers based on event.name (e.g. User.created).

This is the best place to call external APIs.

Existing job processing infrastructure such as sidekiq workers can also be integrated.

Main point is that heavy lifting is done outside of web requests, based on events.

Future Improvements

1. Support concurrency in publisher

Use a pool of worker threads to handle more than 1 event concurrently.

2. Automated Code Generation via Gem

Automate the creation of the schema, model, test, and publisher code through a generator. This generator could be included in a separate gem and required into the main app.

3. Add Multitenant Support

Allow for separate, isolated user spaces.

Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

Please make sure to update tests as appropriate.

License

This project is licensed under the MIT License. See the LICENSE file for details.

About

How to implement an event driven architecture in Ruby on Rails (using Domain Driven Design principles)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published