Update Rails Event Store to v1.0.0 - walkthrough

… and check why 5600+ Rails engineers read also this

Update Rails Event Store to v1.0.0 - walkthrough

Recently I’ve posted a tweet:

Since then we have published 2 more Rails Event Store versions. And we have finally reached a 1.0.0 milestone!

The process of the upgrade between versions is always described in release notes, but here I’ve decided to summarise all changes required and to emphasize the most important ones.

The Ancient Era - versions: .. 0.1.0

Here is nothing to update. No known (public) historical sources. No changelog. The origins of Rails Event Store are hidden in a private repository of one of our customers. It was born as a small tool to help to integrate with 3rd party systems. We’ve started publishing domain events, have some subscribers that have been reacting to the published events. And most important we have started to store the published domain events. All in only 248 lines of code.

The Medieval Period - versions: 0.1.1 .. 0.14.5

This was a violent time, with separate repositories and frequent API changes. No prisoners have been kept, no deprecations warnings have been issued. Also licensing has not yet been clarified. Thankfully I do not need to update these versions.

The strategy I have used to update Rails Event Store in our workshop application was simple: step by step, and prefer small steps. I’ve always updated only to the next version, run bundler, and run all tests to check if all are green all the time.

The Age of Discovery - versions: 0.15.0 .. 0.18.2

The update started here. The version of the rails_event_store in Gemfile was 0.14.3.

After cloning the application repository and make bundle install I’ve needed to start with making test passing. The problem was the ClassyHash gem we are using in the application to define the schema of domain events. The version in Gemfile has not been specified. And in the meantime, the API of the ClassyHash.validate method has changed. It needs to be fixed.

Having all test green I’ve moved to update Rails Event Store. But this time it has been a piece of cake. Just update version in GemFile, bundle install & run the tests. Additionally, I’ve added a rails_event_store-rspec gem and started using RSpec matchers provided by Rails Event Store in tests. Without issues and in ~2 hours I’ve reached the 0.18.2 version.

The biggest discovery in this Age Of Discovery was that there are no surprises here ;)

The Modern Times - versions: 0.19.0 .. 1.0.0

The Modern Times has started with a big milestone - change of database schema (a.k.a V2 schema). The process of generating migration and running it is well described in v0.19.0 release notes but there are additional things to be beware of:

  • The workshop app (this is only a reference application, not production-ready code) uses SQLite as a database (no dependencies, no problems). Before Rails 5.2 the migration created by Rails Event Store migration generator has tried to an create additional index, which was a duplicate of PK index created by SQLite. The solution is described here.
  • I’ve gone straight to 0.20.0 version because missing specification of minimum working activerecord-import gem version.

After solving these issues the first version of the workshop application with the “modern” version of Rails Event Store was ready.

The next noticeable difference (remember I update versions one by one) was 0.26.0. With this version, I’ve to change how subscriptions to events are defined because API has been changed. Also, I’ve started using a new API that allows passing a proc/lambda as a subscriber.

I’ve replaced:

# ./config/initializers/rails_event_store.rb

es.subscribe(OrderList::OrderSubmittedHandler,
    [Orders::OrderSubmitted])

es.subscribe(
    ->(event){ Discounts::Process.perform_later(YAML.dump(event)) },
 [Orders::OrderShipped])

with updated code:

# ./config/initializers/rails_event_store.rb

es.subscribe(OrderList::OrderSubmittedHandler,
    to: [Orders::OrderSubmitted])

es.subscribe(to: [Orders::OrderShipped]) do |event|
  Discounts::Process.perform_later(YAML.dump(event))
end

The 0.27.1 version allowed me to use Arkency’s command_bus gem, which it is from this version included in Rails Event Store. Also here you could no longer compare generated & stored domain event’s metadata because of change in metadata enrichment.

With a 0.29.0 version, I was able to start correlating events using with_metadata method of RailsEventStore::Client. See more how to use it in the documentation. Also the RubyEventStore::Specification::Result has replaced previous reader API methods. All usages of:

client = Rails.configuration.event_store

client.read_all_streams_forward(count:  count, start: start)
client.read_all_streams_backward(count:  count, start: start)
client.read_events_forward(stream_name, count:  count, start: start)
client.read_events_backward(stream_name, count:  count, start: start)
client.read_stream_events_forward(stream_name)
client.read_stream_events_backward(stream_name)

need to be replaced with new read API:

client = Rails.configuration.event_store

client.read.from(start).limit(count).each.to_a
client.read.from(start).limit(count).backward.each.to_a
client.read.stream(stream_name).from(start).limit(count).each.to_a
client.read.stream(stream_name).from(start).limit(count).backward.each.to_a
client.read.stream(stream_name).each.to_a
client.read.stream(stream_name).backward.each.to_a

This change could be done using provided migrator:

bundle exec res-deprecated-read-api-migrator -m FILE_OR_DIRECTORY

Check the release notes for details.

Another API change has been allowed by 0.31.1. But this was just a rename, replacing append_to_stream with append and publish_event with publish. If you use link_to_stream it can be also changed here to link. The old deprecated here method names have been removed in 0.33.0.

With 0.34.0 a database migration was needed to add indexes for searching by event type & limit length of event_id field. And 0.35.0 comes with next data migration - to change data & metadata fields to binary

The Rails Event Store 0.37.0 comes with redesigned aggregate_root gem. The aggregate objects should no longer have load and store methods but you should use AggregateRoot:Repository implement aggregate persistence.

Instead of:

order = Order.new.load("OrderStreamHere")
order.do_something
order.store

you need to:

repository = AggregateRoot::Repository.new
order = repository.load(Order.new, "OrderStreamHere")
order.do_something
repository.store(order, "OrderStreamHere")

or even better:

repository = AggregateRoot::Repository.new
repository.with_aggregate(Order.new, "OrderStreamHere") do |order|
    order.do_something
end

All other versions up to 1.0.0 it’s just updating gem versions (remember to update also rails_event_store-rspec) and checking if everything is ok by running tests.

Other noticeable changes - not covered here

Version 0.40.0:

  • Introduced PipelineMapper that allows composing transformations to build customized mapping solution.

Version 0.31.0:

  • Breaking: RailsEventStore::Client#initialize signature. Out is event_broker:, in subscriptions: and dispatcher:. A dispatcher is no longer an event broker dependency.

Version 0.28.0:

  • Change: Mappers (and serializers) now operate above the repository layer. If you have a custom mapper or serializer move its configuration.
  • Breaking: Metadata keys are limited to symbols. Metadata values are limited to [String, Integer, Float, Date, Time, TrueClass, FalseClass]. Using Hash, Array, or custom objects is no longer supported.
  • Breaking: Using protobuf mapper requires adding protobuf_nested_struct gem.

Version 0.27.0:

  • Breaking: Dropped support for Ruby 2.2. It might continue to work, but we no longer test it and we don’t guarantee it anymore.
  • Breaking: RailsEventStore.event_repository global configuration option was removed. Pass a repository as a dependency when initializing the client.

Version 0.19.0:

  • Breaking: delete_stream no longer removes events.

Ruby & Rails versions

The issue with the additional index for SQLite goes away with the update to Rails 5.2. The support for this Rails version has been added in 0.28.0.

Currently Rails Event Store is tested with Ruby 2.4, 2.5 & 2.6 (it works with 2.7 but there are issues with mutation testing) and with Rails 4.2, 5.0, 5.1, 5.2 (it works with 6.0 but it is not yet included in test matrix).

When in doubts

Read the … manual or call the developer’s police 🤣

You might also like