Skip to content

fast-programmer/outboxer

Repository files navigation

📤 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.

About

Transactional outbox for Ruby on Rails apps

Topics

Resources

License

Code of conduct

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •