Rabbit (Rabbit Messaging) ·
Provides client and server support for RabbitMQ
Installation
gem "rabbit_messaging"
$ bundle install
# --- or ---
$ gem install "rabbit_messaging"
require "rabbit_messaging"
Usage
Configuration
RabbitMQ connection configuration fetched from the
bunny_options
section of/config/sneakers.yml
Rabbit.config
provides setters for following options:group_id
(Symbol
), required
Shared identifier which used to select api. As usual, it should be same as default project_id (I.e. we have project 'support', which runs only one application in production. So on, it's group_id should be :support)
project_id
(Symbol
), required
Personal identifier which used to select exact service. As usual, it should be same as default project_id with optional stage_id. (I.e. we have project 'support', in production it's project_id is :support, but in staging it uses :support1 and :support2 ids for corresponding stages)
exception_notifier
(Proc
) You must provide your own notifier like this to notify about exceptions:
config.exception_notifier = proc { |e| MyCoolNotifier.notify!(e) }
hooks
(Hash
)
:before_fork and :after_fork hooks, used same way as in unicorn / puma / que / etc
environment
(one of:test
,:development
,:production
), default::production
Internal environment of gem.
:test
environment stubs publishing and does not suppress errors:development
environment auto-creates queues and uses default exchange:production
environment enables handlers caching and gets maximum strictness
By default gem skips publishing in test and development environments. If you want to change that then manually set
Rabbit.skip_publishing_in
with an array of environments.Rabbit.skip_publishing_in = %i[test]
receiving_job_class_callable
(Proc
)
Custom ActiveJob subclass to work with received messages. Receives the following attributes as
kwarg
-arguments::arguments
- information about message type (type
), application id (app_id
), message id (message_id
);:delivery_info
- information aboutexchange
,routing_key
, etc;:message
- received RabbitMQ message (often in astring
format);
{ message: '{"hello":"world","foo":"bar"}', delivery_info: { exchange: "some exchange", routing_key: "some_key" }, arguments: { type: "some_successful_event", app_id: "some_group.some_app", message_id: "uuid", } }
before_receiving_hooks, after_receiving_hooks
(Array of Procs
)
Before and after hooks with message processing in the middle. Where
before_receiving_hooks
andafter_receiving_hooks
are empty arrays by default.It's advised to NOT place procs with long execution time inside.
Setup:
config.before_receiving_hooks.append(proc { |, arguments| do_stuff_1 }) config.before_receiving_hooks.append(proc { |, arguments| do_stuff_2 }) config.after_receiving_hooks.append(proc { |, arguments| do_stuff_3 }) config.after_receiving_hooks.append(proc { |, arguments| do_stuff_4 })
Client
Rabbit.publish(
routing_key: :support,
event: :ping,
data: { foo: :bar }, # default is {}
exchange_name: 'fanout', # default is fine too
confirm_select: true, # setting this to false grants you great speed up and absolutelly no guarantees
headers: { "foo" => "bar" }, # custom arguments for routing, default is {}
message_id: "asdadsadsad", # A unique identifier such as a UUID that your application can use to identify the message.
)
This code sends messages via basic_publish with following parameters:
routing_key
:"support"
exchange
:"group_id.project_id.fanout"
(default is"group_id.poject_id"
)mandatory
:true
(same as confirm_select)
It is set to raise error if routing failed
persistent
:true
type
:"ping"
content_type
:"application/json"
(always)app_id
:"group_id.project_id"
Messages are logged to
/log/rabbit.log
Server
Server is supposed to run inside a daemon via the
daemons-rails
gem. Server is run withRabbit::Daemon.run
.before_fork
andafter_fork
procs inRabbit.config
are used to teardown and setup external connections between daemon restarts, for example ORM connectionsAfter the server runs, received messages are handled by
Rabbit::EventHandler
subclasses in two possible ways:- a) Subclasses are selected by following code(by default):
ruby rabbit/handler/#{group_id}/#{event}".camelize.constantize
- b) you can change default behaviour to your own logic by setting the
handler_resolver_callable
config option with aProc
that should return the handler class:ruby Rabbit.config.handler_resolver_callable = -> (group_id, event) { "recivers/#{group_id}/#{event}".camelize.constantize }
- a) Subclasses are selected by following code(by default):
They use powerful Tainbox
api to handle message data. Project_id also passed to them.
If you wish so, you can override initialize(message)
, where message is an object
with simple api (@see lib/rabbit/receiving/message.rb)
Handlers can specify a queue their messages will be put in via a queue_as
class macro (accepts
a string / symbol / block with |message, arguments|
params)
- Received messages are logged to
/log/sneakers.log
, malformed messages are logged to/log/malformed_messages.log
and deleted from queue
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/umbrellio/rabbit_messaging.
License
Released under MIT License
Authors
Team Umbrellio