O objetivo desta GEM é permitir que as Engines que compõem a nova Plataforma da Estante Virutal possam se comunicar sem que estas precisem "se conhecer", garantindo assim um baixo acoplamento entre as Engines.
A solução é baseada no pattern Publish-Subscribe Channel descrito pelo Fowler em seu livro Enterprise Integration Patterns. No caso, o papel do MessageChannel será exercido pelo RabbitMQ.
Como dito anteriormente, esta gem utiliza o RabbitMQ. Por isso precisamos ter esta dependência instalada. Para realizar a instalação basta seguir o passo a passo descrito neste link
Depois, você precisa adicionar um novo source ao seu Gemfile. Este novo source deve ser a primeira linha do seu Gemfile:
source 'https://repo.fury.io/sergioazevedo'
source 'https://rubygems.org'
Se vc estiver instalando em uma Engine deve alterar o arquivo 'suaengine.gemspec' e adicionar a dependencia
s.add_dependency "event","~>1.0.0"
Caso seja um projeto Ruby normal ou uma Rails app adicione a linha abaixo no seu Gemfile:
gem "event","~>1.0.0"
E executar: $ bundle
Os arquivos abaixo são necessários para se configurar esta gem.
config/event.yml
config/initializes/setup_event.rb
Para gerá-los basta rodar a rake task: rake app:event:install
.
####config/event.yml Neste arquivo você deve fornecer as configuracoes para conexão com o Broker RabbitMQ. Mas este arquivo contém uma configuração muito importante, e está na chave: base_routing_key. Você precisa usar nesta chave o nome da sua engine (ou algo semelhante, que identifique o módulo). Exemplo: Imagine o modulo de Ecommerce
development:
base_routing_key: ecommerce
broker:
ip: localhost
port: 5672
username: guest
password: guest
####config/initializers/setup_event.rb Você só vai precisar alterar este arquivo no caso de querer "assinar" algum evento.
Publicar eventos é muito fácil, basta usar Event.pubish.
Event.publish(:sku_added, name: 'Caneta Azul', price: 1.99, qty: 10 )
No exempo acima o nome do evento é :sku_added e os dados do evento estão no hash: {name: 'Caneta Azul', price: 1.99, qty: 10}
###Sobre os Eventos Eventos são sempre coisas que já aconteceram, por este motivo é de boa prática que os nomes dos eventos descrevam claramente que fato ocorreu e com quem. Exemplos abaixo:
- Um produto novo sku foi adicionado - :new_product_added
- Um sku novo foi adicionado - :new_sku_added
- Um sku foi vendido - :sku_saled
- Produto teve seu preço alterado - product_price_updated
Sobre os dados do evento, isto fica a cargo de quem publica o evento. Mas em geral é bacana enviar informações sobre o contexto do evento.
Exemplo:
- Um sku foi vendido
Event.publish(:sku_saled, sku_id: 10 )
- Preço de um sku foi alterado
Event.publish(:sku_price_changed, sku_id: 10, old_price: 1.99, new_price: 2.87 )
Assinar eventos é um processo de duas etapas:
- Escrever uma classe Listener para o evento desejado
- Registrar o Listener para o evento desejado em config/initializes/setup_event.rb
####1. Escrever uma classe Listener para o evento desejado Como dito antes você vai precisar escrever uma classe para cada listener que desejar. Esta classe não precisa herdar de nada, basta que ela tenha os métodos #initialize e notify. O Listener é como um Observer GoF.
Atenção, o listener deve receber toda a informação necessária para sua excução no método de inicialização (new), ou seja, os dados do evento/mensagem.
Exemplo de Listener:
Considere a mensagem abaixo:
Event.publish(:sku_price_changed, sku_id: 10, old_price: 1.99, new_price: 2.87 )
class SkuPriceChangedListener
def initialize(data={})
@sku_id = data[:sku_id]
@old_price = data[:old_price]
@new_price = data[:new_price]
end
def notify
#aqui vai o seu código.
#vc pode, e em geral vai acontecer isso, instanciar um UseCase e executa-lo.
end
end
Por razões de segurança, e para garantia da consistencia dos nossos dados, as operações realizadas por um Listener deve ser idempontentes.
Idempotente quer dizer que múltiplas requisições ao mesmo recurso usando o método devem ter o mesmo resultado que teria uma requisição apenas. A título de curiosidade, idempotente é a propriedade de um número que, multiplicado por ele mesmo, tem ele mesmo como resultado (n x n = n), em termos de números reais, apenas 0 e 1 têm essa propriedade. Em termos de métodos de requisição HTTP, os métodos GET, HEAD, PUT e DELETE são os que possuem a propriedade de ser idempotentes
Em geral, costuma-se criar dentro de app/ uma pasta chamada listeners ou event_listeners.
####2. Registrar o Listener para o evento No arquivo setup_events.rb existe uma seção dedicada ao registro dos listeners. Esta seção vem toda comentada por padrão, veja:
# Register your listeners Here!!!! Example:
# Event.register_listeners do |config|
# config.add_listeners(:event_name, ['EventNameListener'])
# config.add_listeners(:another_event_name, ['AnotherEventListener1', 'Listner2'])
# end
Basta descomentar e seguir como no exemplo. Imaginando que queremos registrar o nosso SkuPriceChangedListener, esta configuracao ficaria assim:
# Register your listeners Here!!!! Example:
Event.register_listeners do |config|
config.add_listeners(:sku_price_changed, ['SkuPriceChanged'])
end
Note que você sempre deve fornecer o nome do Listener com uma String dentro de um Array.
Observação: Como este arquivo setup_events.rb é carregado na inicialização da aplicação, toda vez que você registrar um evento novo vai precisar reinicar a app.
Observação: Atualmente, o producer só consegue enviar mensagens caso haja um consumer.
- Fork it ( https://github.com/[my-github-username]/event/fork )
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create a new Pull Request