euston-daemons 1.0.0-java

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