BunnyPublisher
Ruby publisher(producer) for RabbitMQ based on bunny.
Why?
Bunny is a great RabbitMQ client that allows to implement both consumers & producers. In order to publish a message it requires only few lines of code:
conn = Bunny.new
conn.start
channel = conn.create_channel
exchange = channel.exchange('my_exchange')
exchange.publish('message', routing_key: 'some.key')
But usually more features are requested. Such as:
- Multi-thread environment should re-use AMQP-connection.
- No message should be lost if there is no sutable routing at the moment of publishing.
- Callbacks support (e.g. for logging or metrics)
So publisher implementation becomes more complex and hard to maintain. This project aims to reduce amount of boiler-plate code to write. Just use basic publisher with modules for your needs:
-
BunnyPublisher::Base
- basic publisher with callbacks support. Based on publisher of Sneakers. -
BunnyPublisher::Mandatory
- module for publisher that uses mandatory option to handle unrouted messages -
BunnyPublisher::RPC
- module for publisher to support RPC
Installation
Required ruby version is 2.5. Add this line to your application's Gemfile:
gem 'bunny-publisher'
And then execute:
$ bundle
Or install it yourself as:
$ gem install bunny-publisher
Basic usage
Publisher is ready to be used out of the box
# publishes to default exchange, expects "such.easy" queue to exist
BunnyPublisher.publish 'wow', routing_key: 'such.easy'
Set RABBITMQ_URL
environment variable to connect to custom host/vhost.
Publisher can also be configured
BunnyPublisher.configure do |c|
# custom exchange options
c.exchange = 'custom'
c.exchange_options = { type: 'fanout' }
# custom connection (e.g. with ssl configured)
c.connection = Bunny.new(something: 'custom')
# or just custom options for connection
c.amqp = ENV['CLOUDAMQP_URL']
c.heartbeat = 10
end
Mandatory publishing
The publisher also supports :mandatory option to handle unrouted messages. In case of unrouted message publisher:
- Will create a queue by the name of routing key
- Will bind queue to the exchange
- Publish message again
Configure publisher to use mandatory option
BunnyPublisher.configure do |c|
c.mandatory = true
# ...
end
Publish message with new routing key
BunnyPublisher.publish 'wow', routing_key: 'such.reliable' # this will create "such.reliable" queue
You also can set custom settings for queue definition
BunnyPublisher.configure do |c|
c.mandatory = true
c.queue = 'funnel' # if not set, routing_key is used for the name
c.queue_options = { durable: true }
# ...
end
Remote Procedure Call RPC
Not implemented yet
Test mode
BunnyPublisher also has a test mode which replaces exchange and prevents real connection to RabbitMQ
BunnyPublisher.configure do |c|
c.test = true # or Rails.env.test?
# ...
end
Now publisher has #messages
, #flush!
methods:
describe SomeServiceThatPublishesToRabbitMQ, '#call' do
subject { described_class.new(some: 'attributes').call }
before { BunnyPublisher.flush! }
it 'publishes a message' do
expect { subject }.to change(BunnyPublisher.messages).by(1)
end
end
Testing
Run rabbitmq server (in separate console):
docker run --rm -p 5672:5672 -p 15672:15672 rabbitmq:3.8-management-alpine
Run tests with:
bundle
rake
Use wwtd to run test matrix:
gem install wwtd
wwtd
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/veeqo/bunny-publisher.
License
The gem is available as open source under the terms of the MIT License.