Outboxer is an implementation of the transactional outbox pattern for event driven Ruby on Rails applications.
1. Install gem
bundle add outboxer
bundle install2. Generate schema migrations and tests
bundle exec rails g outboxer:install3. Migrate database
bundle exec rails db:migrate4. Generate event schema and model
bundle exec rails generate model Event type:string created_at:datetime --skip-timestamps
bundle exec rails db:migrate5. Queue outboxer message when event created
# app/models/event.rb
class Event < ApplicationRecord
after_create do |event|
Outboxer::Message.queue(messageable: event)
end
end6. Derive event type
# app/models/accountify/invoice_raised_event.rb
module Accountify
class InvoiceRaisedEvent < Event; end
end7. Create derived event type
bundle exec rails cActiveRecord::Base.logger = Logger.new(STDOUT)
Accountify::InvoiceRaisedEvent.create!(created_at: Time.current)8. Observe transactional consistency
TRANSACTION (0.2ms) BEGIN
Event Create (0.4ms) INSERT INTO "events" ...
Outboxer::Message Create (0.3ms) INSERT INTO "outboxer_messages" ...
TRANSACTION (0.2ms) COMMIT9. Publish event
# bin/outboxer_publisher
Outboxer::Publisher.publish_message do |publisher, message|
# TODO: publish event here
endTo integrate with Active Cable, Sidekiq, Bunny, Kafka, AWS SQS and others, see the publisher integration guide.
To ensure you have end to end coverage:
bundle exec rspec spec/bin/outboxer_publisher
Monitor multithreaded publishers using Outboxer's built-in web UI:
Rails
# config/routes.rb
require 'outboxer/web'
mount Outboxer::Web, at: '/outboxer'Rack
# config.ru
require 'outboxer/web'
map '/outboxer' { run Outboxer::Web }All contributions are welcome!
Open-sourced under LGPL v3.0.