euston-daemons 1.1.0-java → 1.2.0-java

Sign up to get free protection for your applications and to get access to all the features.
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