Zooip/gorg_service

View on GitHub
README.md

Summary

Maintainability
Test Coverage
# GorgService
[![Code Climate](https://codeclimate.com/github/Zooip/gorg_service/badges/gpa.svg)](https://codeclimate.com/github/Zooip/gorg_service) [![Test Coverage](https://codeclimate.com/github/Zooip/gorg_service/badges/coverage.svg)](https://codeclimate.com/github/Zooip/gorg_service/coverage) [![Build Status](https://travis-ci.org/Zooip/gorg_service.svg?branch=master)](https://travis-ci.org/Zooip/gorg_service) [![Gem Version](https://badge.fury.io/rb/gorg_service.svg)](https://badge.fury.io/rb/gorg_service) [![Dependency Status](https://gemnasium.com/badges/github.com/Zooip/gorg_service.svg)](https://gemnasium.com/github.com/Zooip/gorg_service)

Standard RabbitMQ bot used in Gadz.org SOA

## Installation

Add this line to your application's Gemfile:

```ruby
gem 'gorg_service'
```

And then execute:

    $ bundle

Or install it yourself as:

    $ gem install gorg_service

## Setup
  
  Before being used, GorgService must be configured. In Rails app, put it in an Initializer.

```ruby
GorgService.configure do |c|
  # application name for display usage
  c.application_name="My Application Name"
  # application id used to find message from this producer
  c.application_id="my_app_id"

  ## RabbitMQ configuration
  # 
  ### Authentification
  # If your RabbitMQ server is password protected put it here
  #
  # c.rabbitmq_user = nil
  # c.rabbitmq_password = nil
  #  
  ### Network configuration :
  #
  # c.rabbitmq_host = "localhost"
  # c.rabbitmq_port = 5672
  # c.rabbitmq_vhost = "/"
  #
  #
  # c.rabbitmq_event_exchange_name = "exchange"
  #
  # time before trying again on softfail in milliseconds (temporary error)
  # c.rabbitmq_deferred_time = 1800000 # 30min
  # 
  # maximum number of try before discard a message
  # c.rabbitmq_max_attempts = 48 # 24h with default deferring delay
  #
  # The routing key used when sending a message to the central log system (Hardfail or Warning)
  # Central logging is disable if nil
  # c.log_routing_key = nil
  #

 end
```

## Usage

To start the RabbitMQ consummer use :
```ruby
my_service = GorgService.new
my_service.run
```
### Routing and MessageHandler
When running, GorgService act as a consumer on Gadz.org RabbitMQ network.
It bind its queue on the main exchange and subscribes to routing keys with `listen_to`

Each received message will be routed to the corresponding `MessageHandler`. AMQP wildcards are supported.The first key to match the incoming routing key will be used.

A `MessageHandler` is a kind of controller. This is where you the message is processed.
A `MessageHandler` expect a `GorgService::Message` as param of its `initializer`method.

Here is an exemple `MessageHandler` :
```ruby

class ExampleMessageHandler < GorgService::Consumer::MessageHandler::EventHandler

  listen_to "event.user.updated"

  EXPECTED_SCHEMA = {
    "type" => "object",
    "required" => ["user_id"],
    "properties" => {
      "user_id" => {"type" => "integer"}
    }
  }
  
  def validate
    message.validate_with(EXPECTED_SCHEMA)
  end
  
  def process
    begin
        if example=Example.update(message.data[:user_id])
          producer=GorgServiceProducer.new
          event=GorgService::Message.new(
            event: "event.example.updated",
            data: {example_id: example.id}
          )
          producer.publish_message(event)
        else
          raise_hardfail("Unable to update example")
        end
     rescue ApiConnectionError => e
      raise_softfail("Unable to connect to API",error: e)
     end
  end
end
```

As showed in this example,`GorgService::MessageHandler` provides 2 helpers :

 - `raise_hardfail`: This will raise a `HardfailError`exception. The message can't be processed and will never be. It is logged and send back to main exchange for audit purpose.

 - `raise_softfail`: This will raise a `SoftfailError`exception. The message can't be processed at this moment but may be processed in future : connection problems, rate limiting API, etc. It is sent to a deferred queue where it will be delayed for `rabbitmq_deferred_time`millisecconds before being sent back in the main exchange for re-queuing.

Each one of this helpers expect two params :

 - `message` : The information to be displayed in message's error log
 - `exception` (optional) : The runtime exception causing the fail, for debug purpose

### Message structure
`GorgService::Message` is defined [here](https://github.com/Zooip/gorg_service/blob/master/lib/gorg_service/message.rb)

It provides the following attributes :

 - `event` : this is the same as the routing key
 - `id`: message UUID
 - `errors`: A list of `GorgService::Message::ErrorLog`
 - `data`: `Hash` containing the data to be processed
 - `creation_time`: message emission date as `DateTime`
 - `sender` : message producer id


Error log structure :

 - `id` : Error uuid
 - `type` : Type of error (debug, info, warning, softerror, harderror)
 - `sender` : Id of service emitting this error
 - `message` : Error message
 - `debug` : Hash containing debug infos

## To Do

 - Allow disable JSON Schema Validation on incomming messages
 - Message and ErrorLog attributes validation

## Development

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](https://rubygems.org).

## Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/Zooip/gorg_service.


## License

The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).