euston-daemons 1.1.0-java → 1.2.0-java

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.
Files changed (76) hide show
  1. data/Gemfile +1 -0
  2. data/euston-daemons.gemspec +27 -52
  3. data/lib/euston-daemons/euston/daemon.rb +7 -1
  4. data/lib/euston-daemons/euston/daemon_component.rb +9 -49
  5. data/lib/euston-daemons/euston/daemon_component_host.rb +66 -0
  6. data/lib/euston-daemons/euston/daemon_environment.rb +10 -5
  7. data/lib/euston-daemons/euston/exceptions.rb +9 -0
  8. data/lib/euston-daemons/euston/stopwatch.rb +15 -0
  9. data/lib/euston-daemons/pipeline/config/environment.rb +74 -0
  10. data/lib/euston-daemons/pipeline/lib/command_logger/component.rb +54 -0
  11. data/lib/euston-daemons/pipeline/lib/command_logger/log.rb +31 -0
  12. data/lib/euston-daemons/pipeline/lib/command_processor/component.rb +50 -0
  13. data/lib/euston-daemons/pipeline/lib/command_processor/default_handlers/retry_failed_message.rb +34 -0
  14. data/lib/euston-daemons/pipeline/lib/command_processor/failed_message.rb +36 -0
  15. data/lib/euston-daemons/pipeline/lib/daemon.rb +77 -0
  16. data/lib/euston-daemons/pipeline/lib/event_processor/component.rb +67 -0
  17. data/lib/euston-daemons/pipeline/lib/event_processor/default_handlers/message_failure.rb +30 -0
  18. data/lib/euston-daemons/pipeline/lib/event_store_dispatcher/component.rb +68 -0
  19. data/lib/euston-daemons/pipeline/lib/message_buffer/buffer.rb +85 -0
  20. data/lib/euston-daemons/pipeline/lib/message_buffer/component.rb +59 -0
  21. data/lib/euston-daemons/pipeline/lib/snapshotter/component.rb +48 -0
  22. data/lib/euston-daemons/pipeline/rake_task.rb +45 -0
  23. data/lib/euston-daemons/rake_task.rb +40 -19
  24. data/lib/euston-daemons/rake_tasks.rb +1 -3
  25. data/lib/euston-daemons/version.rb +1 -1
  26. data/lib/euston-daemons.rb +3 -1
  27. data/spec/daemons/{command_handler_spec.rb → command_processor_spec.rb} +3 -3
  28. data/spec/daemons/{event_handler_spec.rb → event_processor_spec.rb} +2 -2
  29. data/spec/daemons/{command_buffer_publisher_spec.rb → message_buffer_spec.rb} +19 -23
  30. data/spec/daemons/{snapshot_client_spec.rb → snapshotter_spec.rb} +3 -5
  31. data/spec/spec_helper.rb +23 -9
  32. data/spec/support/filters.rb +4 -5
  33. metadata +73 -88
  34. data/lib/euston-daemons/command_processor_daemon/config/environment.rb +0 -34
  35. data/lib/euston-daemons/command_processor_daemon/lib/clients/command_handler.rb +0 -37
  36. data/lib/euston-daemons/command_processor_daemon/lib/command_handlers/retry_failed_message.rb +0 -35
  37. data/lib/euston-daemons/command_processor_daemon/lib/daemon.rb +0 -22
  38. data/lib/euston-daemons/command_processor_daemon/lib/mongo_models/failed_message.rb +0 -34
  39. data/lib/euston-daemons/command_processor_daemon/rake_task.rb +0 -36
  40. data/lib/euston-daemons/euston/daemon_client.rb +0 -24
  41. data/lib/euston-daemons/event_processor_daemon/config/environment.rb +0 -36
  42. data/lib/euston-daemons/event_processor_daemon/lib/clients/event_handler.rb +0 -42
  43. data/lib/euston-daemons/event_processor_daemon/lib/daemon.rb +0 -24
  44. data/lib/euston-daemons/event_processor_daemon/lib/event_handlers/message_failure.rb +0 -27
  45. data/lib/euston-daemons/event_processor_daemon/rake_task.rb +0 -39
  46. data/lib/euston-daemons/message_buffer_daemon/config/environment.rb +0 -42
  47. data/lib/euston-daemons/message_buffer_daemon/lib/clients/command_buffer_cleanup.rb +0 -9
  48. data/lib/euston-daemons/message_buffer_daemon/lib/clients/command_buffer_publisher.rb +0 -9
  49. data/lib/euston-daemons/message_buffer_daemon/lib/clients/command_logger.rb +0 -9
  50. data/lib/euston-daemons/message_buffer_daemon/lib/clients/euston_exchange_accessors.rb +0 -15
  51. data/lib/euston-daemons/message_buffer_daemon/lib/clients/event_buffer_cleanup.rb +0 -9
  52. data/lib/euston-daemons/message_buffer_daemon/lib/clients/event_buffer_publisher.rb +0 -9
  53. data/lib/euston-daemons/message_buffer_daemon/lib/clients/event_logger.rb +0 -9
  54. data/lib/euston-daemons/message_buffer_daemon/lib/clients/event_store_dispatcher.rb +0 -25
  55. data/lib/euston-daemons/message_buffer_daemon/lib/clients/message_buffer_cleanup.rb +0 -52
  56. data/lib/euston-daemons/message_buffer_daemon/lib/clients/message_buffer_publisher.rb +0 -37
  57. data/lib/euston-daemons/message_buffer_daemon/lib/clients/message_logger.rb +0 -45
  58. data/lib/euston-daemons/message_buffer_daemon/lib/clients/mongo_model_accessors.rb +0 -21
  59. data/lib/euston-daemons/message_buffer_daemon/lib/daemon.rb +0 -17
  60. data/lib/euston-daemons/message_buffer_daemon/lib/mongo_models/command_buffer.rb +0 -11
  61. data/lib/euston-daemons/message_buffer_daemon/lib/mongo_models/command_log.rb +0 -11
  62. data/lib/euston-daemons/message_buffer_daemon/lib/mongo_models/event_buffer.rb +0 -11
  63. data/lib/euston-daemons/message_buffer_daemon/lib/mongo_models/event_log.rb +0 -11
  64. data/lib/euston-daemons/message_buffer_daemon/lib/mongo_models/message_buffer.rb +0 -57
  65. data/lib/euston-daemons/message_buffer_daemon/lib/mongo_models/message_log.rb +0 -29
  66. data/lib/euston-daemons/message_buffer_daemon/rake_task.rb +0 -32
  67. data/lib/euston-daemons/snapshot_daemon/lib/clients/snapshotter.rb +0 -43
  68. data/sample/Rakefile +0 -63
  69. data/sample/amqp_config.yml +0 -14
  70. data/sample/command_handlers.rb +0 -17
  71. data/sample/command_processor_daemon_config.yml +0 -9
  72. data/sample/event_handlers.rb +0 -21
  73. data/sample/event_processor_daemon_config.yml +0 -8
  74. data/sample/message_buffer_daemon_config.yml +0 -8
  75. data/sample/mongoid_config.yml +0 -13
  76. data/sample/pids/.placeholder +0 -0
@@ -0,0 +1,77 @@
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}".to_sym, 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}".to_sym, component
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ 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
@@ -0,0 +1,30 @@
1
+ module Euston
2
+ module Daemons
3
+ module Pipeline
4
+ module EventProcessor
5
+ module DefaultHandlers
6
+ class MessageFailure
7
+ include Euston::EventHandler
8
+
9
+ subscribes :message_failed, 1 do |headers, event|
10
+ headers = event[:message][:headers].dup
11
+ failure = { :message_id => headers.delete(:id),
12
+ :type => headers.delete(:type),
13
+ :version => headers.delete(:version),
14
+ :message_timestamp => headers.delete(:timestamp),
15
+ :routing_key => event[:routing_key],
16
+ :body => event[:message][:body],
17
+ :headers => headers,
18
+ :error => event[:error],
19
+ :backtrace => event[:backtrace],
20
+ :failure_timestamp => Time.now.to_f }
21
+
22
+ failed_messages = CommandProcessor::FailedMessage.new DaemonEnvironment.event_store_mongodb
23
+ failed_messages.log_failure failure
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,68 @@
1
+ module Euston
2
+ module Daemons
3
+ module Pipeline
4
+ module EventStoreDispatcher
5
+ class Component < DaemonComponent
6
+ extend RabbitMq::Exchanges
7
+
8
+ def initialize channel, id = 1, log = Euston::NullLogger.instance
9
+ @channel = channel
10
+ @channel.tx_select
11
+ @id = id
12
+ @log = log
13
+ @event_store = DaemonEnvironment.event_store
14
+ @stopwatch = Stopwatch.new.when(:finished => method(:log_elapsed_time))
15
+ @commands_exchange = self.class.get_exchange channel, :commands
16
+ @events_exchange = self.class.get_exchange channel, :events
17
+ @buffer = MessageBuffer::Buffer.new DaemonEnvironment.event_store_mongodb
18
+ end
19
+
20
+ private
21
+
22
+ def log_elapsed_time elapsed_time
23
+ @log.debug "Event store dispatcher #{@id} dispatched #{@commits_dispatched} commit(s) in #{elapsed_time} sec(s)" if @commits_dispatched > 0
24
+ end
25
+
26
+ def next_iteration
27
+ @commits_dispatched = 0
28
+
29
+ @stopwatch.time do
30
+ begin
31
+ @event_store.take_ownership_of_undispatched_commits @id
32
+ @commits = @event_store.get_undispatched_commits @id
33
+
34
+ begin
35
+ @commits.each do |commit|
36
+ commit.events.each do |event|
37
+ hash = event.to_hash
38
+ @events_exchange.publish ActiveSupport::JSON.encode(hash), self.class.default_publish_options.merge(:routing_key => "events.#{hash[:headers][:type]}")
39
+ end
40
+
41
+ commit.commands.each do |command|
42
+ hash = command.to_hash
43
+
44
+ if hash[:headers][:dispatch_at].nil?
45
+ @commands_exchange.publish ActiveSupport::JSON.encode(hash), self.class.default_publish_options.merge(:routing_key => "commands.#{hash[:headers][:type]}")
46
+ else
47
+ @buffer.enqueue :commands, hash, hash[:headers][:dispatch_at]
48
+ end
49
+ end
50
+ end
51
+
52
+ @channel.tx_commit
53
+ rescue StandardError => e
54
+ @channel.tx_rollback
55
+ raise e
56
+ end
57
+
58
+ @event_store.mark_commits_as_dispatched @commits
59
+
60
+ @commits_dispatched += @commits.size
61
+ end until stopped || @commits.empty?
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,85 @@
1
+ module Euston
2
+ module Daemons
3
+ module Pipeline
4
+ module MessageBuffer
5
+ class Buffer
6
+ def initialize mongodb
7
+ name = 'message_buffer'
8
+ mongodb.create_collection name unless mongodb.collection_names.include? name
9
+
10
+ @name = name
11
+ @collection = mongodb.collection name
12
+
13
+ @collection.ensure_index [ ['message_id', Mongo::ASCENDING] ],
14
+ :unique => false,
15
+ :name => "#{name}_message_id_index"
16
+
17
+ @collection.ensure_index [ ['component_id', Mongo::ASCENDING],
18
+ ['dispatch_at', Mongo::ASCENDING] ],
19
+ :unique => false,
20
+ :name => "#{name}_component_id_dispatch_at_index"
21
+ end
22
+
23
+ attr_reader :name
24
+
25
+ def delete_dispatched_messages component_id
26
+ @collection.remove({ 'component_id' => component_id }, :multi => true)
27
+ end
28
+
29
+ def enqueue exchange, message, dispatch_at = nil
30
+ messages = message
31
+ messages = [{ :hash => message, :dispatch_at => dispatch_at }] unless messages.is_a? Array
32
+
33
+ messages = messages.map do |m|
34
+ message_is_well_formed = m.is_a?(Hash) && m.has_key?(:hash) && m.has_key?(:dispatch_at)
35
+ m = { :hash => m, :dispatch_at => dispatch_at } unless message_is_well_formed
36
+ map_to_document exchange, m
37
+ end
38
+
39
+ @collection.insert(messages) unless messages.empty?
40
+ end
41
+
42
+ def find_dispatchable_messages component_id
43
+ query = { 'component_id' => component_id }
44
+ fields = ['exchange', 'type', 'json']
45
+ sort = [ 'dispatch_at', Mongo::ASCENDING ]
46
+
47
+ @collection.find query, :fields => fields, :sort => sort
48
+ end
49
+
50
+ def get_by_id id
51
+ @collection.find_one 'message_id' => id
52
+ end
53
+
54
+ def take_ownership_of_dispatchable_messages component_id
55
+ new_messages_eligible_for_dispatch = { 'component_id' => '',
56
+ 'dispatch_at' => { '$lte' => Time.now.to_f } }
57
+
58
+ messages_stuck_in_other_components = { 'component_id' => { '$ne' => '' },
59
+ 'dispatch_at' => { '$lte' => Time.now.to_f - 60 } }
60
+
61
+ query = { '$or' => [ new_messages_eligible_for_dispatch, messages_stuck_in_other_components ] }
62
+ doc = { '$set' => { 'component_id' => component_id } }
63
+
64
+ @collection.update query, doc, :multi => true
65
+ end
66
+
67
+ private
68
+
69
+ def map_to_document exchange, message
70
+ hash = message[:hash]
71
+ dispatch_at = (message[:dispatch_at] || Time.now.to_f).to_f
72
+
73
+ { 'message_id' => hash[:headers][:id],
74
+ 'exchange' => exchange,
75
+ 'type' => hash[:headers][:type],
76
+ 'component_id' => '',
77
+ 'dispatch_at' => dispatch_at,
78
+ 'dispatch_at_for_humans' => Time.at(dispatch_at),
79
+ 'json' => ActiveSupport::JSON.encode(hash) }
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,59 @@
1
+ module Euston
2
+ module Daemons
3
+ module Pipeline
4
+ module MessageBuffer
5
+ class Component < Euston::DaemonComponent
6
+ extend RabbitMq::Exchanges
7
+
8
+ def initialize channel, id = 1, logger = Euston::NullLogger.instance
9
+ @channel = channel
10
+ @channel.tx_select
11
+ @id = "message_buffer #{id}"
12
+ @log = logger
13
+ @buffer = Buffer.new DaemonEnvironment.event_store_mongodb
14
+ @stopwatch = Stopwatch.new.when(:finished => method(:log_elapsed_time))
15
+ end
16
+
17
+ private
18
+
19
+ def dispatch_due_messages
20
+ @dispatched_count = 0
21
+
22
+ @stopwatch.time do
23
+ @buffer.take_ownership_of_dispatchable_messages @id
24
+
25
+ begin
26
+ @buffer.find_dispatchable_messages(@id).each do |message|
27
+ exchange = self.class.get_exchange @channel, message['exchange']
28
+ exchange.publish message['json'], self.class.default_publish_options.merge(:routing_key => "#{exchange.name}.#{message['type']}")
29
+ @dispatched_count += 1
30
+ end
31
+
32
+ @channel.tx_commit
33
+ rescue StandardError => e
34
+ @channel.tx_rollback
35
+ raise e
36
+ end
37
+
38
+ @buffer.delete_dispatched_messages @id
39
+ end
40
+
41
+ @dispatched_count
42
+ end
43
+
44
+ def log_elapsed_time elapsed_time
45
+ @log.debug "Message buffer #{@id} dispatched #{@dispatched_count} message(s) in #{elapsed_time} sec(s)" if @dispatched_count > 0
46
+ end
47
+
48
+ def next_iteration
49
+ @messages_dispatched = 0
50
+
51
+ begin
52
+ @messages_dispatched = dispatch_due_messages
53
+ end until stopped || @messages_dispatched.zero?
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,48 @@
1
+ module Euston
2
+ module Daemons
3
+ module Pipeline
4
+ module Snapshotter
5
+ class Component < Euston::DaemonComponent
6
+ def initialize event_store, threshold, id = 1, logger = Euston::NullLogger.instance
7
+ @event_store = event_store
8
+ @threshold = threshold
9
+ @id = id
10
+ @log = logger
11
+ end
12
+
13
+ private
14
+
15
+ def next_iteration
16
+ begin
17
+ stream_heads = @event_store.get_streams_to_snapshot @threshold
18
+ @log.debug "Found #{stream_heads.length} stream(s) eligible for snapshotting (threshold is #{@threshold})" if stream_heads.any?
19
+
20
+ stream_heads.each do |stream_head|
21
+ pair = @event_store.get_snapshot_stream_pair stream_head.stream_id
22
+
23
+ loader = RabbitMq::ConstantLoader.new
24
+ loader.when(:hit => ->(klass) { take_snapshot klass, pair },
25
+ :miss => ->(type) { Safely.report! "Snapshotter was unable to find a class: #{type}" })
26
+
27
+ loader.load pair.stream.committed_headers[:aggregate_type]
28
+ end
29
+ end until stopped || stream_heads.empty?
30
+ end
31
+
32
+ def take_snapshot klass, pair
33
+ instance = klass.hydrate pair.stream, pair.snapshot
34
+ snapshot = instance.take_snapshot
35
+ snapshot = EventStore::Snapshot.new pair.stream.stream_id,
36
+ pair.stream.stream_revision,
37
+ snapshot[:payload],
38
+ :version => snapshot[:version]
39
+
40
+ @log.debug "Writing snapshot: #{snapshot.inspect}"
41
+
42
+ @event_store.add_snapshot snapshot
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,45 @@
1
+ module Euston
2
+ class PipelineRakeTask < Euston::Daemons::RakeTask
3
+ attr_accessor :amqp_config_path,
4
+ :command_handler_namespaces,
5
+ :daemon_config_path,
6
+ :event_handler_namespaces,
7
+ :mongo_config_path
8
+
9
+ def initialize environment
10
+ super(environment, :pipeline_daemon)
11
+ end
12
+
13
+ def before_creating_task
14
+ @daemon_path = File.expand_path(File.dirname __FILE__) + File::SEPARATOR
15
+ @daemon_class = 'Euston::Daemons::Pipeline::Daemon'
16
+ end
17
+
18
+ def load_daemon_config_file
19
+ @data[:daemon_config] = ErbYaml.read @daemon_config_path, @data[:environment]
20
+ end
21
+
22
+ def initialize_settings
23
+ @logger.debug "AMQP config path: #{@amqp_config_path}"
24
+ @data[:amqp_config_path] = @amqp_config_path
25
+
26
+ @logger.debug "Command handler namespaces: #{@command_handler_namespaces}"
27
+ @data[:command_handler_namespaces] = @command_handler_namespaces
28
+
29
+ @logger.debug "Daemon config path: #{@daemon_config_path}"
30
+
31
+ @logger.debug "Event handler namespaces: #{@event_handler_namespaces}"
32
+ @data[:event_handler_namespaces] = @event_handler_namespaces
33
+
34
+ @logger.debug "Mongo config path: #{@mongo_config_path}"
35
+ @data[:mongo_config_path] = @mongo_config_path
36
+ end
37
+
38
+ def load_environment
39
+ @logger.debug "Loading environment"
40
+ require 'euston-daemons/pipeline/config/environment'
41
+
42
+ Euston::Daemons::Pipeline::DaemonEnvironment.new(@data).setup
43
+ end
44
+ end
45
+ end
@@ -15,11 +15,8 @@ module Euston
15
15
  # Daemon class. Must be supplied as a string.
16
16
  attr_accessor :daemon_class
17
17
 
18
- # Logger instance. Defaults to writing to /var/log/euston.log.
19
- attr_accessor :logger
20
-
21
- # # Path to write the daemon pid file to
22
- attr_accessor :pid_path
18
+ # Callable. Receives the daemon environment object to allow the user to perform other related config operations.
19
+ attr_accessor :post_setup_callback
23
20
 
24
21
  # Use verbose output. If this is set to true, the task will print the
25
22
  # executed command to stdout.
@@ -40,11 +37,13 @@ module Euston
40
37
  desc("Run a Euston daemon") unless ::Rake.application.last_comment
41
38
  task name do
42
39
  RakeFileUtils.send(:verbose, verbose) do
40
+ load_daemon_config_file
43
41
  initialize_logger
42
+ initialize_settings
44
43
  write_pid_file
45
44
  log_startup
46
- initialize_settings
47
- load_environment
45
+ env = load_environment
46
+ post_setup_callback.call env unless post_setup_callback.nil?
48
47
  launch_and_wait_for_exit
49
48
  log_shutdown
50
49
  remove_pid_file
@@ -54,16 +53,19 @@ module Euston
54
53
 
55
54
  private
56
55
 
57
- def validate_environment environment
58
- environment = environment.to_s.downcase.to_sym
59
- environments = [:development, :test, :staging, :production]
60
- environment = :development unless environments.include? environment
61
- environment
62
- end
63
-
64
56
  def initialize_logger
65
- @logger ||= Logger.new(STDOUT)
66
- @data[:logger] = @logger
57
+ config = @data[:daemon_config]
58
+ log_path = config[:log_path]
59
+
60
+ raise "Required log path does not exist: #{log_path}" unless Dir.exist? log_path
61
+
62
+ @data[:logger] = @logger = Logger.new(File.join log_path, "#{@name}.#{@environment}.log")
63
+
64
+ begin
65
+ @logger.level = Logger.const_get config[:log_level].upcase.to_sym
66
+ rescue
67
+ @logger.level = Logger::DEBUG
68
+ end
67
69
  end
68
70
 
69
71
  def initialize_settings
@@ -81,6 +83,14 @@ module Euston
81
83
  ns.new(@data).run
82
84
  end
83
85
 
86
+ def load_daemon_config_file
87
+ # virtual
88
+ end
89
+
90
+ def load_environment
91
+ # virtual
92
+ end
93
+
84
94
  def log_shutdown
85
95
  print_log_banner "Daemon shut down: #{@daemon_class}"
86
96
  end
@@ -105,16 +115,27 @@ module Euston
105
115
  File.delete @pid_file rescue Errno::ENOENT
106
116
  end
107
117
 
118
+ def validate_environment environment
119
+ environment = environment.to_s.downcase.to_sym
120
+ environments = [:development, :test, :staging, :production]
121
+ environment = :development unless environments.include? environment
122
+ environment
123
+ end
124
+
108
125
  def write_pid_file
109
- @pid_file = File.join pid_path, "#{@name}.pid"
126
+ pid_path = @data[:daemon_config][:pid_path]
127
+
128
+ raise "Required pid path does not exist: #{pid_path}" unless Dir.exist? pid_path
129
+
130
+ @pid_file = File.join pid_path, "#{@name}.#{@environment}.pid"
110
131
 
111
132
  if defined? Java
112
- @pid = Java::JavaIo::File.new("/proc/self").canonical_file.name
133
+ @pid = java.lang.management.ManagementFactory.getRuntimeMXBean().getName().split('@').first
113
134
  else
114
135
  @pid = File.readlink("/proc/self")
115
136
  end
116
137
 
117
- @logger.debug "Writing pid #{@pid} to #{@pid_file}"
138
+ @logger.error "Writing pid #{@pid} to #{@pid_file}"
118
139
 
119
140
  File.open(@pid_file, 'w') { |f| f.puts @pid }
120
141
  end
@@ -2,6 +2,4 @@ require 'euston-daemons'
2
2
 
3
3
  require 'rake/tasklib'
4
4
  require 'euston-daemons/rake_task'
5
- require 'euston-daemons/command_processor_daemon/rake_task'
6
- require 'euston-daemons/event_processor_daemon/rake_task'
7
- require 'euston-daemons/message_buffer_daemon/rake_task'
5
+ require 'euston-daemons/pipeline/rake_task'
@@ -1,5 +1,5 @@
1
1
  module Euston
2
2
  module Daemons
3
- VERSION = "1.1.0"
3
+ VERSION = "1.2.0"
4
4
  end
5
5
  end
@@ -10,7 +10,9 @@ if RUBY_PLATFORM.to_s == 'java'
10
10
  end
11
11
  end
12
12
 
13
+ require 'euston-daemons/euston/stopwatch'
14
+ require 'euston-daemons/euston/exceptions'
13
15
  require 'euston-daemons/euston/daemon_environment'
14
- require 'euston-daemons/euston/daemon_client'
15
16
  require 'euston-daemons/euston/daemon_component'
17
+ require 'euston-daemons/euston/daemon_component_host'
16
18
  require 'euston-daemons/euston/daemon'
@@ -1,10 +1,10 @@
1
- describe 'command handler client', :purge_event_store, :purge_rabbitmq do
2
- require 'euston-daemons/command_processor_daemon/lib/clients/command_handler'
1
+ describe 'command handler component', :purge_event_store, :purge_rabbitmq do
2
+ require 'euston-daemons/pipeline/lib/command_processor/component'
3
3
 
4
4
  let(:logger) { Euston::NullLogger.instance }
5
5
  let(:handlers) { [] }
6
6
  let(:subscription) { StubRetryingSubscription.new }
7
- let(:client) { Euston::CommandProcessorDaemon::CommandHandler.new @channel, handlers, logger }
7
+ let(:client) { Euston::Daemons::Pipeline::CommandProcessor::Component.new @channel, handlers, 1, logger }
8
8
  let(:aggregate) { Euston::Daemons::SampleModel::Counter2.new }
9
9
  let(:saved_aggregates) { [] }
10
10
 
@@ -1,9 +1,9 @@
1
1
  describe 'event handler client', :purge_event_store, :purge_rabbitmq do
2
- require 'euston-daemons/event_processor_daemon/lib/clients/event_handler'
2
+ require 'euston-daemons/pipeline/lib/event_processor/component'
3
3
 
4
4
  let(:logger) { Euston::NullLogger.instance }
5
5
  let(:subscription) { StubRetryingSubscription.new }
6
- let(:client) { Euston::EventProcessorDaemon::EventHandler.new @channel, reference, logger }
6
+ let(:client) { Euston::Daemons::Pipeline::EventProcessor::Component.new @channel, reference, 1, logger }
7
7
  let(:aggregate) { Euston::Daemons::SampleModel::Counter2.new }
8
8
  let(:saved_aggregates) { [] }
9
9