Rabbit (Rabbit Messaging) · Gem Version Coverage Status

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 about exchange, routing_key, etc;
    • :message - received RabbitMQ message (often in a string 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 and after_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 { |message, arguments| do_stuff_1 })
      config.before_receiving_hooks.append(proc { |message, arguments| do_stuff_2 })
    
      config.after_receiving_hooks.append(proc { |message, arguments| do_stuff_3 })
      config.after_receiving_hooks.append(proc { |message, 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 with Rabbit::Daemon.run. before_fork and after_fork procs in Rabbit.config are used to teardown and setup external connections between daemon restarts, for example ORM connections

  • After 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 a Proc that should return the handler class: ruby Rabbit.config.handler_resolver_callable = -> (group_id, event) { "recivers/#{group_id}/#{event}".camelize.constantize }

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


Supported by Umbrellio