euston-daemons 1.0.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 (34) hide show
  1. data/Gemfile +4 -0
  2. data/Gemfile.lock +101 -0
  3. data/LICENSE +19 -0
  4. data/Rakefile +161 -0
  5. data/euston-daemons.gemspec +69 -0
  6. data/lib/euston-daemons.rb +15 -0
  7. data/lib/euston-daemons/command_processor_daemon/config/environment.rb +14 -0
  8. data/lib/euston-daemons/command_processor_daemon/lib/components/command_handler_component.rb +55 -0
  9. data/lib/euston-daemons/command_processor_daemon/lib/daemon.rb +43 -0
  10. data/lib/euston-daemons/command_processor_daemon/lib/settings.rb +19 -0
  11. data/lib/euston-daemons/command_processor_daemon/rake_task.rb +31 -0
  12. data/lib/euston-daemons/event_processor_daemon/config/environment.rb +20 -0
  13. data/lib/euston-daemons/event_processor_daemon/lib/components/event_handler_component.rb +72 -0
  14. data/lib/euston-daemons/event_processor_daemon/lib/daemon.rb +72 -0
  15. data/lib/euston-daemons/event_processor_daemon/lib/settings.rb +22 -0
  16. data/lib/euston-daemons/event_processor_daemon/rake_task.rb +37 -0
  17. data/lib/euston-daemons/framework/basic_component.rb +33 -0
  18. data/lib/euston-daemons/framework/component_shutdown.rb +22 -0
  19. data/lib/euston-daemons/framework/daemon.rb +27 -0
  20. data/lib/euston-daemons/framework/queue.rb +71 -0
  21. data/lib/euston-daemons/message_buffer_daemon/config/environment.rb +26 -0
  22. data/lib/euston-daemons/message_buffer_daemon/lib/components/buffer_component.rb +74 -0
  23. data/lib/euston-daemons/message_buffer_daemon/lib/components/event_store_component.rb +51 -0
  24. data/lib/euston-daemons/message_buffer_daemon/lib/daemon.rb +48 -0
  25. data/lib/euston-daemons/message_buffer_daemon/lib/message_logger.rb +54 -0
  26. data/lib/euston-daemons/message_buffer_daemon/lib/publisher.rb +56 -0
  27. data/lib/euston-daemons/message_buffer_daemon/lib/read_model/message_buffer.rb +54 -0
  28. data/lib/euston-daemons/message_buffer_daemon/lib/read_model/message_log.rb +36 -0
  29. data/lib/euston-daemons/message_buffer_daemon/lib/settings.rb +14 -0
  30. data/lib/euston-daemons/message_buffer_daemon/lib/subscriber.rb +60 -0
  31. data/lib/euston-daemons/message_buffer_daemon/rake_task.rb +30 -0
  32. data/lib/euston-daemons/rake_task.rb +116 -0
  33. data/lib/euston-daemons/version.rb +5 -0
  34. metadata +235 -0
@@ -0,0 +1,43 @@
1
+ module Euston
2
+ module CommandProcessorDaemon
3
+ class Daemon
4
+ include Euston::Daemon
5
+
6
+ attr_reader :clients,:queue #,:ctx
7
+
8
+ def initialize #(ctx)
9
+ @queue = Queue.new
10
+ # @ctx = ctx
11
+ @clients = {}
12
+
13
+ Settings.client_instances.times do |i|
14
+ @clients["command_component_#{i.succ}"] = CommandHandlerComponent.new
15
+ end
16
+ end
17
+
18
+ def run
19
+ @clients.each do |name, component|
20
+ sleep 0.25
21
+ EUSTON_LOG.debug "Starting component: #{name}"
22
+ component.start
23
+ end
24
+
25
+ EUSTON_LOG.debug "Components started"
26
+
27
+ @clients.each do |name, component|
28
+ EUSTON_LOG.debug("Thread state of #{name}: #{component.thread_state.inspect}")
29
+ end
30
+
31
+ @queue.pop #<-------- stops here until interrupted
32
+
33
+ @clients.each do |name, component|
34
+ EUSTON_LOG.debug "Stopping component: #{name}"
35
+ component.stop
36
+ end
37
+
38
+ report_shutdown_reasons
39
+ EUSTON_LOG.debug "Components stopped"
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,19 @@
1
+ module Euston
2
+ module CommandProcessorDaemon
3
+ module Settings
4
+ def self.configure(cfg=nil)
5
+ @config ||= {}
6
+ @config.merge!(cfg) if cfg && cfg.is_a?(Hash)
7
+ end
8
+ def self.client_instances
9
+ @config[:client_instances] || 1
10
+ end
11
+ def self.mongo_db_name
12
+ @config[:mongo_db_name]
13
+ end
14
+ def self.debug
15
+ @config[:debug]
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,31 @@
1
+ module Euston
2
+ class CommandProcessorRakeTask < Euston::Daemons::RakeTask
3
+ attr_accessor :amqp_config_path, :command_handler_namespaces, :daemon_config_path
4
+
5
+ def initialize
6
+ @command_handler_namespaces = []
7
+ super(:command_processor_daemon)
8
+ end
9
+
10
+ def before_creating_task
11
+ @daemon_path = File.expand_path(File.dirname __FILE__) + File::SEPARATOR
12
+ @daemon_class = 'Euston::CommandProcessorDaemon::Daemon'
13
+ end
14
+
15
+ def initialize_paths
16
+ EUSTON_LOG.debug "AMQP config path: #{@amqp_config_path}"
17
+ Object.const_set :AMQP_CONFIG_PATH, @amqp_config_path
18
+
19
+ EUSTON_LOG.debug "Daemon config path: #{@daemon_config_path}"
20
+ Object.const_set :DAEMON_CONFIG_PATH, @daemon_config_path
21
+
22
+ EUSTON_LOG.debug "Command handler namespaces: #{@command_handler_namespaces}"
23
+ Object.const_set :COMMAND_HANDLER_NAMESPACES, @command_handler_namespaces
24
+ end
25
+
26
+ def load_environment
27
+ EUSTON_LOG.debug "Loading environment"
28
+ require_rel 'config/environment.rb'
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,20 @@
1
+ require_rel '../components'
2
+ require_rel '../lib'
3
+
4
+ Safely::Strategy::Log.logger = EUSTON_LOG
5
+ Cqrs.uuid = Uuid
6
+ AMQP.settings.merge! ErbYaml.read(AMQP_CONFIG_PATH, EUSTON_ENV)
7
+ Euston::EventProcessorDaemon::Settings.configure ErbYaml.read(DAEMON_CONFIG_PATH, EUSTON_ENV)
8
+
9
+ hash = ErbYaml.read(MONGOID_CONFIG_PATH, EUSTON_ENV)
10
+
11
+ read_connection = Mongo::Connection.new hash[:host], hash[:port], :safe => hash[:safe] #, :logger => EUSTON_LOG
12
+
13
+ Mongoid.configure do |config|
14
+ config.master = Mongo::DB.new(hash[:read_model_database], read_connection)
15
+ config.logger = EUSTON_LOG
16
+ end
17
+
18
+ Cqrs::RabbitMq.read_model_mongodb = Mongo::DB.new(hash[:read_model_database], read_connection)
19
+
20
+ I18n.load_path += Dir[I18N_LOCALES_PATH]
@@ -0,0 +1,72 @@
1
+ module Euston
2
+ module EventProcessorDaemon
3
+ class EventHandlerComponent
4
+ include Euston::Daemons::ComponentShutdown
5
+
6
+ attr_reader :channel, :cli_threads
7
+
8
+ def initialize()
9
+ @channel = AMQP::Channel.new
10
+ @channel.prefetch(1)
11
+ @event_handler_bindings = Cqrs::RabbitMq::EventHandlerBindings.new(@channel)
12
+
13
+ if Object.const_defined? 'EVENT_HANDLER_NAMESPACES'
14
+ EVENT_HANDLER_NAMESPACES.each do |handler_namespace|
15
+ ns = Object
16
+ found = true
17
+
18
+ handler_namespace.split('::').each do |c|
19
+ if found && ns.const_defined?(c)
20
+ ns = ns.const_get c.to_sym
21
+ elsif found
22
+ EUSTON_LOG.warn "Couldn't find requested event handler namespace: #{handler_namespace}"
23
+ found = false
24
+ end
25
+ end
26
+
27
+ if found
28
+ EUSTON_LOG.debug "Successfully found event handler namespace: #{handler_namespace}"
29
+ @event_handler_bindings.add_namespace ns
30
+ end
31
+ end
32
+ end
33
+
34
+ @cli_threads = {}
35
+ end
36
+
37
+ def start
38
+ @event_handler_bindings.namespaced_handler_types.each do |namespace, handler_type|
39
+
40
+ @cli_threads["#{namespace}.#{handler_type}"] = Thread.new(namespace, handler_type) do |ns, ht|
41
+ begin
42
+ chan = AMQP::Channel.new
43
+ chan.prefetch(1)
44
+ EUSTON_LOG.debug "EventHandlerBinding for: #{ns}.#{ht}"
45
+ binding = Cqrs::RabbitMq::EventHandlerBinding.new(chan, ns, ht)
46
+ binding.bind
47
+ binding.listen
48
+ rescue => e
49
+ Thread.current[:exception] = e
50
+ ensure
51
+ chan.disconnect
52
+ end
53
+ check_exception_and_shutdown
54
+ end
55
+ end
56
+ end
57
+
58
+ def thread_state
59
+ out = {}
60
+ @cli_threads.each do |k, th|
61
+ out[k] = th.status
62
+ end
63
+ out.inspect
64
+ end
65
+
66
+ def stop
67
+ @cli_threads.values.each { |th| th[:stop] = true }
68
+ @channel.disconnect
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,72 @@
1
+ module Euston
2
+ module EventProcessorDaemon
3
+ class Daemon
4
+ include Euston::Daemon
5
+
6
+ #attr_reader :ctx,:servers,:bus,:queue,:event_handler
7
+ attr_reader :queue, :event_handler
8
+
9
+ def initialize() #ctx)
10
+ # @servers = []
11
+ # @ctx = ctx
12
+ # @queue = Queue.new
13
+
14
+ # bus_client_port = ReadDaemonSettings.bus_port_base
15
+ # bus_server_port = bus_client_port + 10
16
+
17
+ # BusComponentSettings.client_side_bind_address("tcp://*:#{bus_client_port}")
18
+ # BusComponentSettings.server_side_bind_address("tcp://*:#{bus_server_port}")
19
+ # ReadModelComponentSettings.bus_server_side_address("tcp://localhost:#{bus_server_port}")
20
+
21
+ # @bus = BusComponent.new(@ctx)
22
+
23
+ # ReadDaemonSettings.server_instances.times do
24
+ # @servers << ReadModelComponent.new(@ctx)
25
+ # end
26
+
27
+ @queue = Queue.new
28
+ @event_handler = EventHandlerComponent.new
29
+ end
30
+
31
+ def run
32
+ # @bus.daemon = self
33
+ # @bus.start
34
+
35
+ # @servers.each do |ele|
36
+ # sleep(0.5)
37
+ # ele.daemon = self
38
+ # ele.start
39
+ # end
40
+ @event_handler.daemon = self
41
+
42
+ name = 'event_handler'
43
+ EUSTON_LOG.debug "Starting component: #{name}"
44
+ @event_handler.start
45
+
46
+ EUSTON_LOG.debug "Components started"
47
+ EUSTON_LOG.debug "Thread state of #{name}: #{@event_handler.thread_state.inspect}"
48
+
49
+ # EUSTON_LOG.debug @bus.thread_state.inspect
50
+
51
+ # @servers.each do |svr|
52
+ # EUSTON_LOG.debug "Server thread status: #{svr.thread_state}"
53
+ # end
54
+
55
+ @queue.pop #<-------- stops here until interrupted
56
+
57
+ #exiting
58
+ # @servers.each do |ele|
59
+ # ele.stop
60
+ # end
61
+ # sleep(0.6)
62
+ # @bus.stop
63
+
64
+ EUSTON_LOG.debug "Stopping component: #{name}"
65
+ @event_handler.stop
66
+
67
+ report_shutdown_reasons
68
+ EUSTON_LOG.debug "Components stopped"
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,22 @@
1
+ module Euston
2
+ module EventProcessorDaemon
3
+ module Settings
4
+ def self.configure(cfg=nil)
5
+ @config ||= {}
6
+ @config.merge!(cfg) if cfg && cfg.is_a?(Hash)
7
+ end
8
+ def self.server_instances
9
+ @config[:server_instances] || 2
10
+ end
11
+ def self.bus_port_base
12
+ (@config[:zmq_base_port] || 8200).to_i
13
+ end
14
+ def self.mongo_db_name
15
+ @config[:mongo_db_name]
16
+ end
17
+ def self.debug
18
+ @config[:debug]
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,37 @@
1
+ module Euston
2
+ class EventProcessorRakeTask < Euston::Daemons::RakeTask
3
+ attr_accessor :amqp_config_path, :daemon_config_path, :event_handler_namespaces, :i18n_locales_path, :mongoid_config_path
4
+
5
+ def initialize
6
+ @event_handler_namespaces = []
7
+ super(:event_processor_daemon)
8
+ end
9
+
10
+ def before_creating_task
11
+ @daemon_path = File.expand_path(File.dirname __FILE__) + File::SEPARATOR
12
+ @daemon_class = 'Euston::EventProcessorDaemon::Daemon'
13
+ end
14
+
15
+ def initialize_paths
16
+ EUSTON_LOG.debug "AMQP config path: #{@amqp_config_path}"
17
+ Object.const_set :AMQP_CONFIG_PATH, @amqp_config_path
18
+
19
+ EUSTON_LOG.debug "Daemon config path: #{@daemon_config_path}"
20
+ Object.const_set :DAEMON_CONFIG_PATH, @daemon_config_path
21
+
22
+ EUSTON_LOG.debug "Event handler namespaces: #{@event_handler_namespaces}"
23
+ Object.const_set :EVENT_HANDLER_NAMESPACES, @event_handler_namespaces
24
+
25
+ EUSTON_LOG.debug "i18n locales path: #{@i18n_locales_path}"
26
+ Object.const_set :I18N_LOCALES_PATH, @i18n_locales_path
27
+
28
+ EUSTON_LOG.debug "Mongoid config path: #{@mongoid_config_path}"
29
+ Object.const_set :MONGOID_CONFIG_PATH, @mongoid_config_path
30
+ end
31
+
32
+ def load_environment
33
+ EUSTON_LOG.debug "Loading environment"
34
+ require_rel 'config/environment.rb'
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,33 @@
1
+ module Euston
2
+ module Daemons
3
+ class BasicComponent
4
+ include Euston::Daemons::ComponentShutdown
5
+
6
+ attr_reader :client, :cli_thread
7
+
8
+ def initialize(hosted_object)
9
+ @client = hosted_object
10
+ end
11
+
12
+ def start
13
+ @cli_thread = Thread.new do
14
+ begin
15
+ @client.start
16
+ rescue => e
17
+ Thread.current[:exception] = e
18
+ end
19
+ check_exception_and_shutdown
20
+ end
21
+ end
22
+
23
+ def thread_state
24
+ @cli_thread.status
25
+ end
26
+
27
+ def stop
28
+ @cli_thread[:stop] = true
29
+ @client.disconnect if @client.respond_to?(:disconnect)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,22 @@
1
+ module Euston
2
+ module Daemons
3
+ module ComponentShutdown
4
+ attr_writer :daemon
5
+
6
+ def check_exception_and_shutdown(errors=[])
7
+ if errors.compact.empty?
8
+ errors << Thread.current[:exception]
9
+ return if errors.compact.empty?
10
+ end
11
+ errors.compact.each do |e|
12
+ if e.respond_to?(:cause) #its a serious (Java?) exception
13
+ Thread.current[:stop] = true
14
+ @daemon.irrecoverable_signal_from_component! e
15
+ else
16
+ Safely.report! e
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,27 @@
1
+ module Euston
2
+ module Daemon
3
+ def errors
4
+ @errors ||= Queue.new
5
+ end
6
+
7
+ def irrecoverable_signal_from_component!(e)
8
+ self.errors.push e
9
+ @queue.push "SHUTDOWN"
10
+ end
11
+
12
+ def report_shutdown_reasons
13
+ sleep(0.25)
14
+ reports = []
15
+ until self.errors.empty? do
16
+ e = self.errors.pop(true) rescue nil
17
+ next if e.nil?
18
+ case e
19
+ when NativeException
20
+ Safely.report!(e.cause)
21
+ else
22
+ Safely.report!(e)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,71 @@
1
+ class RabbitMQClient
2
+ class Queue
3
+ include Hollywood
4
+
5
+ attr_writer :timeout
6
+
7
+ def delivery_timeout
8
+ @timeout ||= 500
9
+ end
10
+
11
+ def safe_subscribe
12
+ _consumer = self.consumer
13
+ until Thread.current[:stop] do
14
+ safe_subscribe_with_timeout(_consumer, self.delivery_timeout)
15
+ end
16
+ end
17
+
18
+ def safe_handle_message(msg)
19
+ begin
20
+ message = JSON.parse_sym(msg.body)
21
+ begin
22
+ callback :message_received, message
23
+ msg.ack!
24
+ rescue ::EventStore::ConcurrencyError
25
+ msg.reject! true #requeue
26
+ rescue => e
27
+ callback :message_failed, message, e, msg
28
+ Safely.report! e
29
+ end
30
+ rescue => e
31
+ callback :message_decode_failed, msg.body, e
32
+ msg.ack!
33
+ Safely.report! e
34
+ end
35
+ end
36
+
37
+ def consumer(auto_ack=false)
38
+ consumer = QueueingConsumer.new(@channel)
39
+ @channel.basic_consume(@name, auto_ack, consumer)
40
+ consumer
41
+ end
42
+
43
+ def safe_subscribe_with_timeout(consumer, timeout=500)
44
+ loop do
45
+ delivery = nil
46
+ begin
47
+ delivery = consumer.next_delivery(timeout)
48
+ rescue NativeException => e
49
+ Thread.current[:exception] = e
50
+ break
51
+ end
52
+ break if delivery.nil?
53
+ remsg = ReactiveMessage.new(@channel, delivery, String.from_java_bytes(delivery.get_body))
54
+ safe_handle_message remsg
55
+ @channel.basic_ack(delivery.envelope.delivery_tag, false) if remsg.should_acknowledge?
56
+ end
57
+ end
58
+ end
59
+
60
+ class ReactiveMessage
61
+ def reject(opts={})
62
+ self.reject!(opts.fetch(:requeue, true))
63
+ end
64
+ def ack(multiple=false)
65
+ self.ack!
66
+ end
67
+ def method()
68
+ self.envelope
69
+ end
70
+ end
71
+ end