euston-daemons 1.0.5 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +4 -1
- data/Rakefile +2 -3
- data/euston-daemons.gemspec +50 -39
- data/lib/euston-daemons.rb +14 -1
- data/lib/euston-daemons/euston/daemon.rb +99 -0
- data/lib/euston-daemons/euston/daemon_component.rb +25 -0
- data/lib/euston-daemons/euston/daemon_component_host.rb +66 -0
- data/lib/euston-daemons/euston/daemon_environment.rb +59 -0
- data/lib/euston-daemons/euston/exceptions.rb +9 -0
- data/lib/euston-daemons/euston/stopwatch.rb +15 -0
- data/lib/euston-daemons/pipeline/config/environment.rb +78 -0
- data/lib/euston-daemons/pipeline/lib/command_logger/component.rb +54 -0
- data/lib/euston-daemons/pipeline/lib/command_logger/log.rb +31 -0
- data/lib/euston-daemons/pipeline/lib/command_processor/component.rb +50 -0
- data/lib/euston-daemons/pipeline/lib/command_processor/default_commands/retry_failed_message.rb +13 -0
- data/lib/euston-daemons/pipeline/lib/command_processor/default_handlers/retry_failed_message.rb +34 -0
- data/lib/euston-daemons/pipeline/lib/command_processor/failed_message.rb +36 -0
- data/lib/euston-daemons/pipeline/lib/daemon.rb +85 -0
- data/lib/euston-daemons/pipeline/lib/event_processor/component.rb +67 -0
- data/lib/euston-daemons/pipeline/lib/event_processor/default_handlers/message_failure.rb +30 -0
- data/lib/euston-daemons/pipeline/lib/event_store_dispatcher/component.rb +68 -0
- data/lib/euston-daemons/pipeline/lib/message_buffer/buffer.rb +85 -0
- data/lib/euston-daemons/pipeline/lib/message_buffer/component.rb +59 -0
- data/lib/euston-daemons/pipeline/lib/snapshotter/component.rb +48 -0
- data/lib/euston-daemons/pipeline/rake_task.rb +49 -0
- data/lib/euston-daemons/rake_task.rb +63 -66
- data/lib/euston-daemons/rake_tasks.rb +3 -5
- data/lib/euston-daemons/version.rb +1 -1
- data/spec/daemons/command_processor_spec.rb +48 -0
- data/spec/daemons/event_processor_spec.rb +55 -0
- data/spec/daemons/message_buffer_spec.rb +106 -0
- data/spec/daemons/snapshotter_spec.rb +96 -0
- data/spec/spec_helper.rb +91 -0
- data/spec/support/factories/commands.rb +16 -0
- data/spec/support/factories/commit.rb +7 -0
- data/spec/support/factories/event_message.rb +12 -0
- data/spec/support/factories/events.rb +8 -0
- data/spec/support/filters.rb +13 -0
- data/spec/support/sample_model/commands.rb +14 -0
- data/spec/support/sample_model/counter.rb +36 -0
- data/spec/support/sample_model/counter2.rb +46 -0
- data/spec/support/stub_retrying_subscription.rb +9 -0
- metadata +131 -67
- data/lib/euston-daemons/command_processor_daemon/config/environment.rb +0 -25
- data/lib/euston-daemons/command_processor_daemon/lib/components/command_handler_component.rb +0 -56
- data/lib/euston-daemons/command_processor_daemon/lib/daemon.rb +0 -43
- data/lib/euston-daemons/command_processor_daemon/lib/settings.rb +0 -22
- data/lib/euston-daemons/command_processor_daemon/rake_task.rb +0 -34
- data/lib/euston-daemons/event_processor_daemon/config/environment.rb +0 -25
- data/lib/euston-daemons/event_processor_daemon/lib/components/event_handler_component.rb +0 -58
- data/lib/euston-daemons/event_processor_daemon/lib/daemon.rb +0 -71
- data/lib/euston-daemons/event_processor_daemon/lib/settings.rb +0 -26
- data/lib/euston-daemons/event_processor_daemon/rake_task.rb +0 -37
- data/lib/euston-daemons/framework/basic_component.rb +0 -33
- data/lib/euston-daemons/framework/channel_thread.rb +0 -22
- data/lib/euston-daemons/framework/component_shutdown.rb +0 -22
- data/lib/euston-daemons/framework/daemon.rb +0 -27
- data/lib/euston-daemons/framework/handler_bindings_component.rb +0 -56
- data/lib/euston-daemons/framework/queue.rb +0 -71
- data/lib/euston-daemons/message_buffer_daemon/config/environment.rb +0 -28
- data/lib/euston-daemons/message_buffer_daemon/lib/components/buffer_component.rb +0 -73
- data/lib/euston-daemons/message_buffer_daemon/lib/components/event_store_component.rb +0 -52
- data/lib/euston-daemons/message_buffer_daemon/lib/daemon.rb +0 -48
- data/lib/euston-daemons/message_buffer_daemon/lib/message_logger.rb +0 -54
- data/lib/euston-daemons/message_buffer_daemon/lib/publisher.rb +0 -56
- data/lib/euston-daemons/message_buffer_daemon/lib/read_model/message_log.rb +0 -36
- data/lib/euston-daemons/message_buffer_daemon/lib/settings.rb +0 -14
- data/lib/euston-daemons/message_buffer_daemon/lib/subscriber.rb +0 -60
- data/lib/euston-daemons/message_buffer_daemon/rake_task.rb +0 -30
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'i18n'
|
2
|
+
require 'hot_bunnies'
|
3
|
+
require 'macaddr'
|
4
|
+
require 'euston-rabbitmq'
|
5
|
+
|
6
|
+
require 'euston-daemons/pipeline/lib/command_processor/failed_message'
|
7
|
+
require 'euston-daemons/pipeline/lib/command_processor/default_handlers/retry_failed_message'
|
8
|
+
require 'euston-daemons/pipeline/lib/command_processor/component'
|
9
|
+
require 'euston-daemons/pipeline/lib/command_logger/log'
|
10
|
+
require 'euston-daemons/pipeline/lib/command_logger/component'
|
11
|
+
require 'euston-daemons/pipeline/lib/event_processor/default_handlers/message_failure'
|
12
|
+
require 'euston-daemons/pipeline/lib/event_processor/component'
|
13
|
+
require 'euston-daemons/pipeline/lib/event_store_dispatcher/component'
|
14
|
+
require 'euston-daemons/pipeline/lib/message_buffer/buffer'
|
15
|
+
require 'euston-daemons/pipeline/lib/message_buffer/component'
|
16
|
+
require 'euston-daemons/pipeline/lib/snapshotter/component'
|
17
|
+
require 'euston-daemons/pipeline/lib/daemon'
|
18
|
+
|
19
|
+
module Euston
|
20
|
+
module Daemons
|
21
|
+
module Pipeline
|
22
|
+
class DaemonEnvironment < Euston::DaemonEnvironment
|
23
|
+
class << self
|
24
|
+
attr_accessor :command_processors,
|
25
|
+
:command_handler_namespaces,
|
26
|
+
:command_loggers,
|
27
|
+
:command_log_ignores,
|
28
|
+
:event_handler_namespaces,
|
29
|
+
:event_processors,
|
30
|
+
:event_store_dispatchers,
|
31
|
+
:event_store_dispatcher_wait_time,
|
32
|
+
:message_buffers,
|
33
|
+
:message_buffer_wait_time,
|
34
|
+
:snapshotters,
|
35
|
+
:snapshotter_wait_time,
|
36
|
+
:snapshot_threshold,
|
37
|
+
:user_defined_components
|
38
|
+
end
|
39
|
+
|
40
|
+
def initialize data
|
41
|
+
@logger = data[:logger]
|
42
|
+
@daemon_config = data[:daemon_config]
|
43
|
+
@i18n_locales_path = @daemon_config[:i18n_locales_path]
|
44
|
+
|
45
|
+
@amqp_config = ErbYaml.read data[:amqp_config_path], data[:environment]
|
46
|
+
@mongo_config = ErbYaml.read data[:mongo_config_path], data[:environment]
|
47
|
+
|
48
|
+
self.class.command_handler_namespaces = data[:command_handler_namespaces]
|
49
|
+
self.class.event_handler_namespaces = data[:event_handler_namespaces]
|
50
|
+
self.class.user_defined_components = data[:user_defined_components]
|
51
|
+
|
52
|
+
self.class.command_processors = @daemon_config[:command_processors].to_i
|
53
|
+
self.class.command_loggers = @daemon_config[:command_loggers].to_i
|
54
|
+
self.class.command_log_ignores = @daemon_config[:command_log_ignores]
|
55
|
+
self.class.event_processors = @daemon_config[:event_processors].to_i
|
56
|
+
self.class.event_store_dispatchers = @daemon_config[:event_store_dispatchers].to_i
|
57
|
+
self.class.event_store_dispatcher_wait_time = @daemon_config[:event_store_dispatcher_wait_time].to_f
|
58
|
+
self.class.message_buffers = @daemon_config[:message_buffers].to_i
|
59
|
+
self.class.message_buffer_wait_time = @daemon_config[:message_buffer_wait_time].to_f
|
60
|
+
self.class.snapshotters = @daemon_config[:snapshotters].to_i
|
61
|
+
self.class.snapshotter_wait_time = @daemon_config[:snapshotter_wait_time].to_f
|
62
|
+
self.class.snapshot_threshold = @daemon_config[:snapshot_threshold].to_i
|
63
|
+
end
|
64
|
+
|
65
|
+
def setup
|
66
|
+
setup_safely @daemon_config[:hoptoad_key]
|
67
|
+
setup_amqp @amqp_config
|
68
|
+
setup_mongo @mongo_config
|
69
|
+
setup_euston @mongo_config[:event_store_database]
|
70
|
+
|
71
|
+
I18n.load_path += Dir[@i18n_locales_path] unless @i18n_locales_path.nil?
|
72
|
+
|
73
|
+
self.class
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Euston
|
2
|
+
module Daemons
|
3
|
+
module Pipeline
|
4
|
+
module CommandLogger
|
5
|
+
class Component < Euston::DaemonComponent
|
6
|
+
extend RabbitMq::Exchanges
|
7
|
+
extend RabbitMq::Queues
|
8
|
+
|
9
|
+
def initialize channel, id = 1, logger = Euston::NullLogger.instance
|
10
|
+
@id = id
|
11
|
+
@log = logger
|
12
|
+
@channel = channel
|
13
|
+
@channel.prefetch = 1
|
14
|
+
@command_log = Log.new DaemonEnvironment.event_store_mongodb
|
15
|
+
@exchange = self.class.get_exchange channel, :commands
|
16
|
+
@queue = self.class.get_queue channel, @command_log.name
|
17
|
+
@queue.bind @exchange, :routing_key => "#{@exchange.name}.#"
|
18
|
+
|
19
|
+
@queue.when(:message_decode_failed => method(:log_failure),
|
20
|
+
:message_failed => method(:message_failed),
|
21
|
+
:message_received => method(:write_message_to_log))
|
22
|
+
|
23
|
+
@consumer = @queue.consumer
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def log_failure message, error
|
29
|
+
return if ignorable_exception? error
|
30
|
+
|
31
|
+
text = "Command logger #{@id} failed.\n [Error] #{error.message}\n [Payload] #{message}"
|
32
|
+
err = Euston::RabbitMq::MessageDecodeFailedError.new text
|
33
|
+
err.set_backtrace error.backtrace
|
34
|
+
|
35
|
+
Safely.report! err
|
36
|
+
end
|
37
|
+
|
38
|
+
def message_failed message, error, reactive_message
|
39
|
+
log_failure message, error
|
40
|
+
reactive_message.ack
|
41
|
+
end
|
42
|
+
|
43
|
+
def next_iteration
|
44
|
+
@queue.safe_subscribe_with_timeout @consumer
|
45
|
+
end
|
46
|
+
|
47
|
+
def write_message_to_log message
|
48
|
+
@command_log.write_command message unless DaemonEnvironment.command_log_ignores.include? message[:headers][:type]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Euston
|
2
|
+
module Daemons
|
3
|
+
module Pipeline
|
4
|
+
module CommandLogger
|
5
|
+
class Log
|
6
|
+
def initialize mongodb
|
7
|
+
@name = 'command_log'
|
8
|
+
mongodb.create_collection @name unless mongodb.collection_names.include? @name
|
9
|
+
|
10
|
+
@collection = mongodb.collection @name
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :name
|
14
|
+
|
15
|
+
def write_command command
|
16
|
+
timestamp = Time.now.to_f
|
17
|
+
|
18
|
+
doc = { '_id' => command[:headers][:id],
|
19
|
+
'type' => command[:headers][:type],
|
20
|
+
'version' => command[:headers][:version],
|
21
|
+
'timestamp' => timestamp,
|
22
|
+
'timestamp_for_humans' => Time.at(timestamp),
|
23
|
+
'json' => ActiveSupport::JSON.encode(command) }
|
24
|
+
|
25
|
+
@collection.insert doc
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Euston
|
2
|
+
module Daemons
|
3
|
+
module Pipeline
|
4
|
+
module CommandProcessor
|
5
|
+
class Component < Euston::DaemonComponent
|
6
|
+
include Euston::CommandHandlerPrivateMethodNames
|
7
|
+
|
8
|
+
def initialize channel, handlers, id = 1, logger = Euston::NullLogger.instance
|
9
|
+
@channel = channel
|
10
|
+
@channel.prefetch = 1
|
11
|
+
@handlers = handlers
|
12
|
+
@id = id
|
13
|
+
@log = logger
|
14
|
+
@process_method = method(:process_message)
|
15
|
+
@stopwatch = Stopwatch.new.when(:finished => method(:log_elapsed_time))
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def next_iteration
|
21
|
+
Euston::RabbitMq::RetryingSubscription.new(@channel, :command_handlers, @log)
|
22
|
+
.when(:message_received => @process_method)
|
23
|
+
.subscribe
|
24
|
+
end
|
25
|
+
|
26
|
+
def process_message message
|
27
|
+
@stopwatch.time do
|
28
|
+
command_headers = CommandHeaders.from_hash(message[:headers]).freeze
|
29
|
+
command_body = message[:body].freeze
|
30
|
+
|
31
|
+
handler_type = command_headers.type.to_s.camelize.to_sym
|
32
|
+
reference = @handlers.find { |reference| reference.name == handler_type }
|
33
|
+
|
34
|
+
if reference.nil?
|
35
|
+
Euston::CommandBus.publish command_headers, command_body, @log
|
36
|
+
else
|
37
|
+
handler_method_name = self.class.command_handler_method_name command_headers.version
|
38
|
+
reference.handler.new.send handler_method_name, command_headers, command_body
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def log_elapsed_time elapsed_time
|
44
|
+
@log.debug "Command handler client #{@id} processed a message in #{elapsed_time} sec(s)"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/euston-daemons/pipeline/lib/command_processor/default_commands/retry_failed_message.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
module Euston
|
2
|
+
module Daemons
|
3
|
+
module Pipeline
|
4
|
+
module CommandProcessor
|
5
|
+
module DefaultCommands
|
6
|
+
class RetryFailedMessage < Euston::Command
|
7
|
+
validates :id, :presence => true, :format => { :with => /^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$/ }
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/euston-daemons/pipeline/lib/command_processor/default_handlers/retry_failed_message.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
module Euston
|
2
|
+
module Daemons
|
3
|
+
module Pipeline
|
4
|
+
module CommandProcessor
|
5
|
+
module DefaultHandlers
|
6
|
+
class RetryFailedMessage
|
7
|
+
include Euston::CommandHandler
|
8
|
+
|
9
|
+
version 1 do |headers, command|
|
10
|
+
failed_messages = FailedMessage.new DaemonEnvironment.event_store_mongodb
|
11
|
+
message = failed_messages.get_by_id command[:id]
|
12
|
+
|
13
|
+
unless message.nil?
|
14
|
+
routing_key = message['routing_key']
|
15
|
+
exchange = routing_key.split('.').first
|
16
|
+
|
17
|
+
headers = message['headers'].merge(:id => command[:id],
|
18
|
+
:type => message['type'],
|
19
|
+
:version => message['version'] )
|
20
|
+
|
21
|
+
retry_message = { :headers => headers, :body => message['body'] }
|
22
|
+
|
23
|
+
buffer = MessageBuffer::Buffer.new DaemonEnvironment.event_store_mongodb
|
24
|
+
buffer.enqueue exchange, retry_message
|
25
|
+
|
26
|
+
failed_messages.remove_by_id command[:id]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Euston
|
2
|
+
module Daemons
|
3
|
+
module Pipeline
|
4
|
+
module CommandProcessor
|
5
|
+
class FailedMessage
|
6
|
+
def initialize mongodb
|
7
|
+
name = 'failed_messages'
|
8
|
+
mongodb.create_collection name unless mongodb.collection_names.include? name
|
9
|
+
|
10
|
+
@collection = mongodb.collection name
|
11
|
+
@collection.ensure_index [ ['failure_timestamp', Mongo::ASCENDING] ], :unique => false, :name => 'failed_messages_failure_timestamp_index'
|
12
|
+
end
|
13
|
+
|
14
|
+
def get_by_id id
|
15
|
+
@collection.find_one({ '_id' => id })
|
16
|
+
end
|
17
|
+
|
18
|
+
def find_all
|
19
|
+
@collection.find({}, { :sort => [ 'failure_timestamp', Mongo::DESCENDING ] })
|
20
|
+
end
|
21
|
+
|
22
|
+
def log_failure failure
|
23
|
+
failure.recursive_stringify_keys!
|
24
|
+
failure['_id'] = failure.delete 'message_id'
|
25
|
+
|
26
|
+
@collection.save(failure, :safe => { :fsync => true })
|
27
|
+
end
|
28
|
+
|
29
|
+
def remove_by_id id
|
30
|
+
@collection.remove({ '_id' => id }, :safe => { :fsync => true })
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module Euston
|
2
|
+
module Daemons
|
3
|
+
module Pipeline
|
4
|
+
class Daemon < Euston::Daemon
|
5
|
+
private
|
6
|
+
|
7
|
+
def env
|
8
|
+
DaemonEnvironment
|
9
|
+
end
|
10
|
+
|
11
|
+
def post_shutdown_cleanup
|
12
|
+
env.amqp_connection.close
|
13
|
+
end
|
14
|
+
|
15
|
+
def pre_registration_setup
|
16
|
+
channel = env.amqp_connection.create_channel
|
17
|
+
|
18
|
+
begin
|
19
|
+
handler_finder = RabbitMq::HandlerFinder.new [AggregateRoot, Euston::CommandHandler], @log
|
20
|
+
handler_finder.namespaces.push Pipeline::CommandProcessor::DefaultHandlers, *DaemonEnvironment.command_handler_namespaces
|
21
|
+
@command_handler_references = handler_finder.find
|
22
|
+
|
23
|
+
binder = RabbitMq::CommandHandlerBinder.new channel, @command_handler_references, @log
|
24
|
+
binder.ensure_bindings_exist
|
25
|
+
|
26
|
+
handler_finder = RabbitMq::HandlerFinder.new [Euston::EventHandler], @log
|
27
|
+
handler_finder.namespaces.push Pipeline::EventProcessor::DefaultHandlers, *DaemonEnvironment.event_handler_namespaces
|
28
|
+
@event_handler_references = handler_finder.find
|
29
|
+
|
30
|
+
binder = RabbitMq::EventHandlerBinder.new channel, @event_handler_references, @log
|
31
|
+
binder.ensure_bindings_exist
|
32
|
+
rescue NativeException => e
|
33
|
+
@log.error "Caught the following native exception:\n\n#{e}\n\nDid you forget to create your rabbitmq vhost and user for this environment?"
|
34
|
+
raise e
|
35
|
+
ensure
|
36
|
+
channel.close
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def register_components
|
41
|
+
(1..env.command_loggers).each do |i|
|
42
|
+
component = CommandLogger::Component.new env.amqp_connection.create_channel, i, @log
|
43
|
+
register_component "command_logger_#{i}".to_sym, component
|
44
|
+
end
|
45
|
+
|
46
|
+
(1..env.command_processors).each do |i|
|
47
|
+
component = CommandProcessor::Component.new env.amqp_connection.create_channel, @command_handler_references, i, @log
|
48
|
+
register_component "command_processor_#{i}", component
|
49
|
+
end
|
50
|
+
|
51
|
+
(1..env.event_store_dispatchers).each do |i|
|
52
|
+
component = EventStoreDispatcher::Component.new env.amqp_connection.create_channel, "#{Mac.addr.to_s} #{i}", @log
|
53
|
+
component = register_component "event_store_dispatcher_#{i}", component
|
54
|
+
component.wait_time = env.event_store_dispatcher_wait_time
|
55
|
+
end
|
56
|
+
|
57
|
+
(1..env.message_buffers).each do |i|
|
58
|
+
component = MessageBuffer::Component.new env.amqp_connection.create_channel, "#{Mac.addr.to_s} #{i}", @log
|
59
|
+
component = register_component "message_buffer_#{i}", component
|
60
|
+
component.wait_time = env.message_buffer_wait_time
|
61
|
+
end
|
62
|
+
|
63
|
+
(1..env.snapshotters).each do |i|
|
64
|
+
component = Snapshotter::Component.new Euston::Repository.event_store, env.snapshot_threshold, i, @log
|
65
|
+
component = register_component "snapshotter_#{i}", component
|
66
|
+
component.wait_time = env.snapshotter_wait_time
|
67
|
+
end
|
68
|
+
|
69
|
+
(1..env.event_processors).each do |i|
|
70
|
+
component = EventProcessor::Component.new env.amqp_connection.create_channel, @event_handler_references, i, @log
|
71
|
+
register_component "event_processor_#{i}", component
|
72
|
+
end
|
73
|
+
|
74
|
+
env.user_defined_components.each do |udc|
|
75
|
+
udc[:quantity].times do |i|
|
76
|
+
component = udc[:factory_method].call env, i, @log
|
77
|
+
component = register_component "#{udc[:name]}_#{i}", component
|
78
|
+
component.wait_time = udc[:wait_time] || 0.2
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Euston
|
2
|
+
module Daemons
|
3
|
+
module Pipeline
|
4
|
+
module EventProcessor
|
5
|
+
class Component < Euston::DaemonComponent
|
6
|
+
include Euston::EventHandlerPrivateMethodNames
|
7
|
+
|
8
|
+
def initialize channel, references, id = 1, logger = Euston::NullLogger.instance
|
9
|
+
@channel = channel
|
10
|
+
@channel.prefetch = 1
|
11
|
+
@id = id
|
12
|
+
@references = references
|
13
|
+
@log = logger
|
14
|
+
@process_method = method(:process_message)
|
15
|
+
@stopwatch = Stopwatch.new.when(:finished => method(:log_elapsed_time))
|
16
|
+
|
17
|
+
@subscriptions = @references.map do |r|
|
18
|
+
{ :reference => r,
|
19
|
+
:subscription => RabbitMq::RetryingSubscription.new(@channel, r.name.to_s.underscore, @log)
|
20
|
+
.when(:message_received => @process_method) }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def next_iteration
|
27
|
+
@subscriptions.each do |s|
|
28
|
+
@reference = s[:reference]
|
29
|
+
s[:subscription].get
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def process_message message
|
34
|
+
@stopwatch.time do
|
35
|
+
event_headers = EventHeaders.from_hash message[:headers]
|
36
|
+
event_body = message[:body]
|
37
|
+
|
38
|
+
handler_is_aggregate_root = @reference.handler.include? Euston::AggregateRoot
|
39
|
+
|
40
|
+
if handler_is_aggregate_root
|
41
|
+
id_getter_method = self.class.id_from_event_method_name event_headers.type, event_headers.version
|
42
|
+
id = @reference.handler.send id_getter_method, event_body
|
43
|
+
|
44
|
+
raise "Unable to extract the aggregate root id from an #{event_headers.type} event. Did you forget to add an { :id => :field_name } argument to your subscribes block?" if id.nil?
|
45
|
+
|
46
|
+
handler_instance = Euston::Repository.find @reference.handler, id
|
47
|
+
handler_instance.log = @log
|
48
|
+
handler_instance.consume_event_subscription event_headers.freeze, event_body.freeze
|
49
|
+
|
50
|
+
Euston::Repository.save handler_instance
|
51
|
+
else
|
52
|
+
handler_method = self.class.event_handler_method_name event_headers.type, event_headers.version
|
53
|
+
handler_instance = @reference.handler.new
|
54
|
+
handler_instance.log = @log if handler_instance.respond_to? :log=
|
55
|
+
handler_instance.send handler_method, event_headers.freeze, event_body.freeze
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def log_elapsed_time elapsed_time
|
61
|
+
@log.debug "Event handler client #{@reference.name.to_s.underscore} processed a message in #{elapsed_time} sec(s)"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|