# Outboxer ## Background Typically in event driven Ruby on Rails applications: 1. a domain event model is created in an SQL database table 2. a sidekiq worker is queued to handle the domain event asynchronously ## Problem As these two operations span multiple database types (SQL and redis), they can not be combined into a single atomic operation using a transaction. If either step fails, inconsistencies can occur. ## Solution Outboxer is a simple Ruby on Rails implementation of the [transactional outbox pattern](https://microservices.io/patterns/data/transactional-outbox.html): a well established solution to this problem. It ensures both operations succeed _eventually_, or both fail. ### Getting started ### Installation 1. Add the Outboxer gem to your application's Gemfile: ```ruby gem 'outboxer' ``` 2. Install the Outboxer gem: ```bash bundle install ``` 3. Generate the migration and publisher files ```bash bin/rails generate outboxer:install ``` ### Usage #### 1. Include `Outboxer::Outboxable` into your existing Message model ```ruby class Message < ApplicationRecord include Outboxer::Outboxable end ``` #### 2. Update the generated bin/publish block e.g. ```ruby Outboxer::Publisher.publish do |args| logger = args.logger message = args.message logger.info("[#{message.id}] publishing") HardJob.perform_async({ "message_id" => message.id }) logger.info("[#{message.id}] published") end ``` #### 3. Migrate the database ```bash bin/rake db:migrate ``` #### 4. Run the publisher ```bash bin/publisher ``` ## Implementation 1. when an `ActiveRecord` model that includes `Outbox::Outboxable` is created, an `unpublished` `Outboxer::Message` is automatically created in the same transaction, with `Outboxer::Message#message` polymorphically assigned to the original model 2. When the publisher finds a new `unpublished` `Outboxer::Message`, it yields to a user-supplied block and then: - removes it if the task completes successfully - marks it as failed and records the error if there's a problem To see all the parts working together in a single place, check out the [publisher_spec.rb](https://github.com/fast-programmer/outboxer/blob/master/spec/outboxer/publisher_spec.rb) ## Motivation Outboxer was created with 4 key benefits in mind: 1. speed of integration into existing Ruby on Rails applications (< 1 hour) 2. comprehensive documentation that is easy to understand 3. high reliability in production environments (100% code coverage) 4. forever free to use in commerical applications (MIT licence) ## Contributing Bug reports and pull requests are welcome on GitHub at https://github.com/fast-programmer/outboxer. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/fast-programmer/outboxer/blob/main/CODE_OF_CONDUCT.md). ## License The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). ## Code of Conduct Everyone interacting in the Outboxer project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/fast-programmer/outboxer/blob/main/CODE_OF_CONDUCT.md).