Project

outboxer

0.0
No release in over a year
Transactional outbox implementation for event driven Ruby on Rails applications that use SQL
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies

Runtime

 Project Readme

📤 Outboxer

Gem Version Coverage Status Join our Discord

Outboxer is an implementation of the transactional outbox pattern for Ruby on Rails applications.

It helps you migrate to event-driven architecture with at least once delivery guarantees.

Quickstart

1. Install gem

bundle add outboxer
bundle install

2. Generate schema migrations, publisher script and tests

bundle exec rails g outboxer:install

3. Migrate database

bundle exec rails db:migrate

4. Generate event schema and model

bundle exec rails generate model Event type:string created_at:datetime --skip-timestamps
bundle exec rails db:migrate

5. Queue outboxer message after event created

# app/models/event.rb

class Event < ApplicationRecord
  after_create do |event|
    Outboxer::Message.queue(messageable: event)
  end
end

6. Derive event type

# app/models/accountify/invoice_raised_event.rb

module Accountify
  class InvoiceRaisedEvent < Event; end
end

7. Create derived event type

bundle exec rails c
ActiveRecord::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)  COMMIT

8. Publish outboxer messages

# bin/outboxer_publisher

Outboxer::Publisher.publish_messages(batch_size: 1_000, concurrency: 10) do |publisher, messages|
  begin
    # TODO: publish messages here
  rescue => error
    Outboxer::Publisher.update_messages(
      id: publisher[:id],
      failed_messages: messages.map do |message|
        {
          id: message[:id],
          exception: {
            class_name: error.class.name,
            message_text: error.message,
            backtrace: error.backtrace.join("\n")
          }
        }
      end)
  else
    Outboxer::Publisher.update_messages(
      id: publisher[:id],
      published_message_ids: messages.map { |message| message[:id] })
  end
end

To integrate with Sidekiq, Bunny, Kafka and AWS SQS see the publisher block examples.

Testing

To ensure you have end to end coverage:

bundle exec rspec spec/bin/outboxer_publisher

Monitoring

Monitor using the built-in web UI:

Publishers

Screenshot 2025-04-30 at 6 25 06 pm

Messages

Screenshot 2025-04-30 at 6 25 37 pm

Rails

# config/routes.rb

require 'outboxer/web'

mount Outboxer::Web, at: '/outboxer'

Rack

# config.ru

require 'outboxer/web'

map '/outboxer' { run Outboxer::Web }

Contributing

All contributions are welcome!

License

Open-sourced under LGPL v3.0.