Skip to content

Commit

Permalink
Reorganized infrastructure code, particularly event buses, so that li…
Browse files Browse the repository at this point in the history
…bzeromq is not required unless EventBus::Zero is used
  • Loading branch information
cavalle committed May 31, 2011
1 parent 4cda5a3 commit 0eb4a55
Show file tree
Hide file tree
Showing 16 changed files with 186 additions and 186 deletions.
7 changes: 4 additions & 3 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ gem 'rails', '3.0.0'

gem 'uuidtools'
gem 'ohm'
gem 'carrot'
gem 'ffi-rzmq'
gem 'amqp', :require => 'mq'

gem 'carrot', :require => false
gem 'ffi-rzmq', :require => false
gem 'amqp', :require => false

group :development, :test do
gem 'rspec-rails'
Expand Down
10 changes: 4 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@ For persistence the app uses [Redis](http://code.google.com/p/redis/). So a Redi

$ brew install redis
$ redis-server

You also need libzeromq:

$ brew install zeromq

With all that set, the test suite should pass by just running:

Expand Down Expand Up @@ -59,9 +55,11 @@ This is the equivalent to the missing `app/models` and you'll find the entities

Reports are subscribed to events from the domain model and update themselves according to those events. That way they are always in sync but totally uncoupled from the domain model. The reporting repository is denormalized and persisted with Redis.

**app/infrastructure**
**lib/infrastructure**

Infrastructure libraries. Most of the magic is here. Including implementations of the Event Bus using different technologies (ZeroMQ, AMQP, Redis…)

Typically the contents of this directory would be inside `lib` (or a plugin or gem) but, for development purposes, it turned out more convenient to put them in directory added to the `load_path`
Configuration and initialization can be found at `config/initializers/infrastructure.rb` (if you want to try alternative Event Buses you should look here)

**spec/acceptance**

Expand Down
175 changes: 0 additions & 175 deletions app/infrastructure/event_bus.rb

This file was deleted.

2 changes: 1 addition & 1 deletion config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class Application < Rails::Application
# -- all .rb files in that directory are automatically loaded.

# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/extras)
config.autoload_paths += %W(#{config.root}/lib/infrastructure)

# Only load the plugins named here, in the order given (default is alphabetical).
# :all can be used as a placeholder for all plugins not explicitly named.
Expand Down
2 changes: 1 addition & 1 deletion config/initializers/infrastructure.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Rails.application.class.configure do
config.event_bus = 'RedisEventBus'
config.event_bus = 'EventBus::Redis'
config.event_subscribers = %w{ClientReport ClientDetailsReport AccountDetailsReport MoneyTransferSaga}
config.to_prepare { EventBus.init }
end
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
11 changes: 11 additions & 0 deletions lib/infrastructure/event_bus.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module EventBus
class << self
attr_accessor :current
delegate :publish, :subscribe, :wait_for_events, :start, :purge, :stop, :to => :current

def init
EventBus.current = Rails.configuration.event_bus.constantize.new
Rails.configuration.event_subscribers.each(&:constantize)
end
end
end
41 changes: 41 additions & 0 deletions lib/infrastructure/event_bus/amqp.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
require 'carrot'
require 'mq'

class EventBus::AMQP
def publish(event)
Carrot.queue('events').publish(event.id)
end

def subscriptions(event_name)
@subscriptions ||= Hash.new
@subscriptions[event_name.to_s] ||= Set.new
end

def subscribe(event_name, &handler)
subscriptions(event_name.to_s) << handler
end

def wait_for_events
sleep(0.15) # next_tick
end

def purge
Carrot.queue("events").purge
end

def start
AMQP.start do
MQ.new.queue("events").subscribe do |event_id|
event = Event[event_id]
subscriptions(event.name).each do |subscription|
subscription.call(event)
end
end
end
end

def stop
AMQP.stop { EM.stop }
wait_for_events
end
end
21 changes: 21 additions & 0 deletions lib/infrastructure/event_bus/in_process.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
class EventBus::InProcess
def publish(event)
subscriptions(event.name).each do |subscription|
subscription.call(event)
end
end

def subscriptions(event_name)
@subscriptions ||= Hash.new
@subscriptions[event_name] ||= Set.new
end

def subscribe(event_name, &handler)
subscriptions(event_name) << handler
end

def wait_for_events; end
def purge; end
def start; end
def stop; end
end
35 changes: 35 additions & 0 deletions lib/infrastructure/event_bus/redis.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
class EventBus::Redis
def publish(event)
Redis.new.publish "events", event.id
end

def subscriptions(event_name)
@subscriptions ||= Hash.new
@subscriptions[event_name.to_s] ||= Set.new
end

def subscribe(event_name, &handler)
subscriptions(event_name.to_s) << handler
end

def wait_for_events
sleep(0.05) # next_tick
end

def purge
Redis.new.del "events"
end

def start
Redis.new.subscribe("events") do |on|
on.message do |channel, event_id|
event = Event[event_id]
subscriptions(event.name).each do |subscription|
subscription.call(event)
end
end
end
end

def stop; end
end
Loading

0 comments on commit 0eb4a55

Please sign in to comment.