euston-daemons 1.0.5 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|