A simple wrapper gem to aid with producing events to a message queue, using Bunny, in a standardized and uniform way across multiple microservices.
Rather than using Bunny directly, this gem allows an application to define "Event Definitions" which can be defined and published in a modular way. This ensures that when you are producing a message, your application logic shouldn't care about how the message is produced (E.g. your controller shouldn't care or know anything about what exchange to publish a message to, only the BunnyEvent that has been defined cares)
Current Features and limitation:
- Allows a bunny connection to initialise the system
- Allows the definition of abstract events to be used application-wide
- Customization of exchange and queue options when producing an event
- By default, only initialises the exchange and queues on the first publish. This can be overriden with
opts[:always_create_when_publishing]
Add this line to your application's Gemfile:
gem 'bunny_events'
And then execute:
$ bundle
Or install it yourself as:
$ gem install bunny_events
To initialise the system with Rails, create a new intiailizer:
# config/initializers/bunny-events.rb
if !Rails.env.test?
$BUNNY_EVENTS = BunnyEvents.new
$BUNNY_EVENTS.init Bunny.new("amqp://rabbitmq:rabbitmq@rabbit1:5672").start
end
Events can then be created in app/events:
require 'bunny_event'
class MyTestEvent
include BunnyEvent
# define the event options for queueing this event. Each event type can have different options.
event_options :exchange => "test_exchange",
:exchange_opts => {
:type => :fanout
}
# We can define what the message payload looks like here.
def initialize(msg)
@message = "My test message is #{msg}"
end
end
To use Bunny Events in tests, you can initialize a new instance of the system before every test (or just a single test) with BunnyMock
before(:each) do
@mock = BunnyMock.new.start
$BUNNY_EVENTS = BunnyEvents.new
$BUNNY_EVENTS.init @mock
end
Note: This requires the bunny-mock
gem to be installed in your test environment
To produce an event to the message queue, we must first define an event. In app/events/my_test_event.rb
require 'bunny_event'
class MyTestEvent
include BunnyEvent
# define the event options for queueing this event. Each event type can have different options.
event_options :exchange => "test_exchange",
:exchange_opts => {
:type => :fanout
},
:queues =>
{
:some_queue => {
:opts => {
:durable => true
},
:routing_key => ""
}
}
# We can define what the message payload looks like here.
def initialize(msg)
@message = "My test message is #{msg}"
end
end
We can change the payload in the initialize
method, allowing us complete control over what data is used to create the message.
def initialize(user, page)
@message = {
:user_id => user.id,
:user_name => user.name,
:page => page.url,
:timestamp => Time.now.to_i
}.to_json
end
This ensures complete control over how your application produces a message, enabling your application to utilise JSON, AVRO, or just plain old strings.
Publishing the event requires the use of the BunnyEvents class
# Create event, passing in whatever data is needed
event = MyTestEvent.new "This is a test event"
# Use the BunnyEvents system to publish this event
bunny_events = BunnyEvents.new
bunny_events.init Bunny.new("amqp://rabbitmq:rabbitmq@rabbit1:5672").start
bunny_events.publish event
When publishing, a custom routing key can also be used
bunny_events.publish event, "some_routing_key"
When defining an event, many options can be set via the event_options class method.
exchange
- Name of the exchange this event will publish it's messages toexchange_opts
- Bunny-specific options for creating an exchange. See http://rubybunny.info/articles/exchanges.html for more information.queues
- A hash of queues to be created and bound to the exchange. Each key consists of the name of the queue and the value is another hash, with the following options:opts
- Bunny-specific options fo creating a queuerouting_key
- Key used for binding this queue to the exchangeignore_bind
- Can be used to override the binding. Defaults tofalse
. If true, will not bind this queue to the exchange. Is useful when utilising the default exchange.
always_create_when_publishing
- Overrides the queue/exchange creation process to run every time a message is processed. Default:false
routing_key
- The default routing key used for all messages pushed for this event. Can be changed when publishing a message E.g.bunny_events.publish event, "custom_routing_key"
require 'bunny_event'
# This is done once as part of the configuration step, usually in a rails initializer, or at the start of your application
bunny_events = BunnyEvents.new
bunny_events.init Bunny.new("amqp://rabbitmq:rabbitmq@rabbit1:5672").start
# Event definitions are defined in classes, in rails, we generally use app/messages
class MyTestEvent
include BunnyEvent
# define the event options for queueing this event. Each event type can have different options.
event_options :exchange => "test_exchange",
:exchange_opts => {
:type => :fanout
},
:queues =>
{
:some_queue => {
:opts => {
:durable => true
},
:routing_key => ""
}
}
# We can define what the message payload looks like here.
def initialize(msg)
@message = "My test message is #{msg}"
end
end
# When we want to create a new instance of an event, we create and publish the object
event = MyTestEvent.new "test"
bunny_events.publish event
After checking out the repo, run bin/setup
to install dependencies. Then, run rake spec
to run the tests. You can also run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
. To release a new version, update the version number in version.rb
, and then run bundle exec rake release
, which will create a git tag for the version, push git commits and tags, and push the .gem
file to rubygems.org.
Bug reports and pull requests are welcome on GitHub at https://github.com/Nexus-Mods/bunny_events
The gem is available as open source under the terms of the MIT License.