AceMQ for Rails

Rails integration for AceMQ over AMQP: one connection for the process, configured the Rails way; consumers written as classes and run in a process of their own; a health check that composes into whatever readiness endpoint the application already has.

It is a thin layer. The library underneath is where publishing, retries, dead-lettering, codecs and the wire contract live, and none of that is rewritten here. What this adds is the four things a Rails application needs and a library cannot supply: a place for configuration, a place for the connection, a process for the consumers, and the executor around a handler that makes ActiveRecord usable from a thread Rails never made.

# config/acemq.yml
shared:
  shop
  topology:
    exchanges:
      - { shop-events, topic }
    queues:
      - { shop.orders, true }
    bindings:
      - { shop.orders, shop-events, "order.#" }

production:
  <%= ENV["ACEMQ_URL"] %>
# app/controllers/orders_controller.rb
def create
  order = Order.create!(order_params)
  AceMQ::Rails.publish(order.as_json, "order.placed",
                       "shop-events", "order.placed.v2")
  head 
end
# app/consumers/orders_consumer.rb
class OrdersConsumer < AceMQ::Rails::Consumer
  queue "shop.orders"

  def call(message)
    Fulfilment.begin!(message.payload)
    accept
  end
end
$ bundle exec acemq-consumer

That last line is the design, not an implementation detail. Consumers do not run inside Puma, and consumers.md is the argument at length.

Where to go next

Start here Getting started
Reference Configuration — every setting
Usage Publishing · Consumers · Topology · Serialization · Testing
Security TLS, credentials, certificates, payload encryption
Patterns From Rails · Outbox · Idempotency · Saga · Request/reply · Scheduling · Streams
Operations Shutdown and the drain · Health · Observability · Interceptors · Eager loading and reloading
Design Why this is not an ActiveJob adapter
Support Enterprise support

Versions

Ruby 3.1 and later
Rails 7.1, 7.2 and 8.x. Rails 8 needs Ruby 3.2, which is Rails' constraint rather than one this gem adds
acemq-amqp ~> 0.7.14 — every 0.7.x from 0.7.14, and the next minor is looked at before it ships here
Transport bunny ~> 2.23, named by the application. The library declares no runtime dependencies at all

The constraint on the library is three components on purpose: ~> 0.7 would be pessimistic on the major and would quietly admit a 0.8 that changed something this gem is written against. A weekly job checks that the constraint still admits the newest release, because a constraint that has stopped doing so looks exactly like one that still does until somebody looks.

What it is not