modern_times 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. data/LICENSE.txt +201 -0
  2. data/README.rdoc +143 -0
  3. data/Rakefile +28 -0
  4. data/VERSION +1 -0
  5. data/examples/simple/.gitignore +2 -0
  6. data/examples/simple/README +24 -0
  7. data/examples/simple/bar_worker.rb +6 -0
  8. data/examples/simple/baz_worker.rb +8 -0
  9. data/examples/simple/hornetq.yml +14 -0
  10. data/examples/simple/manager.rb +17 -0
  11. data/examples/simple/publish.rb +35 -0
  12. data/lib/modern_times/base/supervisor.rb +97 -0
  13. data/lib/modern_times/base/supervisor_mbean.rb +30 -0
  14. data/lib/modern_times/base/worker.rb +55 -0
  15. data/lib/modern_times/base.rb +3 -0
  16. data/lib/modern_times/exception.rb +4 -0
  17. data/lib/modern_times/hornetq/client.rb +53 -0
  18. data/lib/modern_times/hornetq/marshal_strategy/json.rb +17 -0
  19. data/lib/modern_times/hornetq/marshal_strategy/ruby.rb +17 -0
  20. data/lib/modern_times/hornetq/marshal_strategy/string.rb +17 -0
  21. data/lib/modern_times/hornetq/marshal_strategy.rb +3 -0
  22. data/lib/modern_times/hornetq/publisher.rb +72 -0
  23. data/lib/modern_times/hornetq/supervisor.rb +19 -0
  24. data/lib/modern_times/hornetq/supervisor_mbean.rb +12 -0
  25. data/lib/modern_times/hornetq/worker.rb +121 -0
  26. data/lib/modern_times/hornetq.rb +11 -0
  27. data/lib/modern_times/loggable.rb +23 -0
  28. data/lib/modern_times/manager.rb +92 -0
  29. data/lib/modern_times/manager_mbean.rb +36 -0
  30. data/lib/modern_times/railsable.rb +132 -0
  31. data/lib/modern_times/thread.rb +16 -0
  32. data/lib/modern_times.rb +13 -0
  33. data/test/base/worker_test.rb +38 -0
  34. data/test/messaging/worker_manager_test.rb +58 -0
  35. data/test/messaging/worker_test.rb +58 -0
  36. data/test/worker_manager_test.rb +48 -0
  37. metadata +123 -0
@@ -0,0 +1,4 @@
1
+ module ModernTimes
2
+ class Exception < ::Exception
3
+ end
4
+ end
@@ -0,0 +1,53 @@
1
+ require 'hornetq'
2
+
3
+ # Handle Messaging and Queuing
4
+ module ModernTimes
5
+ module HornetQ
6
+ module Client
7
+ # Singleton-ize
8
+ extend self
9
+
10
+ # Initialize the messaging system and connection pool for this VM
11
+ def init(config)
12
+ @config = config
13
+ @connection = ::HornetQ::Client::Connection.new(@config[:connection])
14
+ # Let's not create a session_pool unless we're going to use it
15
+ @session_pool_mutex = Mutex.new
16
+
17
+ at_exit do
18
+ close
19
+ end
20
+ end
21
+
22
+ def invm?
23
+ @connection.invm?
24
+ end
25
+
26
+ # Create a session targeted for a consumer (producers should use the session_pool)
27
+ def create_consumer_session
28
+ @connection.create_session(config[:session])
29
+ end
30
+
31
+ def session_pool
32
+ # Don't use the mutex unless we have to!
33
+ return @session_pool if @session_pool
34
+ @session_pool_mutex.synchronize do
35
+ # if it's been created in between the above call and now, return it
36
+ return @session_pool if @session_pool
37
+ return @session_pool = @connection.create_session_pool(config[:session])
38
+ end
39
+ end
40
+
41
+ def close
42
+ ModernTimes.logger.info "Closing #{self.name}"
43
+ @session_pool.close if @session_pool
44
+ @connection.close if @connection
45
+ end
46
+
47
+ def config
48
+ raise "#{self.name} never had it's init method called" unless @config
49
+ @config
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,17 @@
1
+ module ModernTimes
2
+ module HornetQ
3
+ module MarshalStrategy
4
+ module JSON
5
+ def marshal(session, object, durable)
6
+ message = session.create_message(::HornetQ::Client::Message::TEXT_TYPE, durable)
7
+ message.body = object.to_json
8
+ message
9
+ end
10
+
11
+ def unmarshal(msg)
12
+ JSON::Parser.new(msg.body).parse
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module ModernTimes
2
+ module HornetQ
3
+ module MarshalStrategy
4
+ module Ruby
5
+ def marshal(session, object, durable)
6
+ message = session.create_message(::HornetQ::Client::Message::BYTES_TYPE, durable)
7
+ message.body = ::Marshal.dump(object)
8
+ message
9
+ end
10
+
11
+ def unmarshal(msg)
12
+ ::Marshal.load(msg.body)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module ModernTimes
2
+ module HornetQ
3
+ module MarshalStrategy
4
+ module String
5
+ def marshal(session, object, durable)
6
+ message = session.create_message(::HornetQ::Client::Message::TEXT_TYPE, durable)
7
+ message.body = object.to_s
8
+ message
9
+ end
10
+
11
+ def unmarshal(msg)
12
+ msg.body
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,3 @@
1
+ require 'modern_times/hornetq/marshal_strategy/json'
2
+ require 'modern_times/hornetq/marshal_strategy/ruby'
3
+ require 'modern_times/hornetq/marshal_strategy/string'
@@ -0,0 +1,72 @@
1
+ require 'hornetq'
2
+
3
+ # Protocol independent class to handle Publishing
4
+ module ModernTimes
5
+ module HornetQ
6
+ class Publisher
7
+
8
+ # TODO: Possible performance enhancements on producer
9
+ # setDisableMessageID()
10
+ # setDisableMessageTimeStamp()
11
+ # See http://hornetq.sourceforge.net/docs/hornetq-2.1.2.Final/user-manual/en/html/perf-tuning.html
12
+ # Create producer pool as per above section 46.6?
13
+ def initialize(address, options={})
14
+ @address = address
15
+ @durable = !!options[:durable]
16
+ if options[:marshal].nil?
17
+ marshal_module = MarshalStrategy::Ruby
18
+ elsif options[:marshal].kind_of? Symbol
19
+ marshal_module = case options[:marshal]
20
+ when :ruby then MarshalStrategy::Ruby
21
+ when :string then MarshalStrategy::String
22
+ when :json then MarshalStrategy::JSON
23
+ else raise "Invalid marshal strategy: #{options[:marshal]}"
24
+ end
25
+ elsif options[:marshal].kind_of? Module
26
+ marshal_module = options[:marshal]
27
+ else
28
+ raise "Invalid marshal strategy: #{options[:marshal]}"
29
+ end
30
+ self.extend marshal_module
31
+ end
32
+
33
+ # Publish the given object to the address.
34
+ def publish(object)
35
+ Client.session_pool.producer(@address) do |session, producer|
36
+ message = marshal(session, object, @durable)
37
+ first_time = true
38
+ begin
39
+ producer.send(message)
40
+ rescue Java::org.hornetq.api.core.HornetQException => e
41
+ ModernTimes.logger.warn "Received producer exception: #{e.message} with code=#{e.cause.code}"
42
+ if first_time && e.cause.code == Java::org.hornetq.api.core.HornetQException::UNBLOCKED
43
+ ModernTimes.logger.info "Retrying the send"
44
+ first_time = false
45
+ retry
46
+ else
47
+ raise
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ # For non-configured Rails projects, The above publish method will be overridden to
54
+ # call this publish method instead which calls all the HornetQ workers that
55
+ # operate on the given address.
56
+ def dummy_publish(object)
57
+ @@worker_instances.each do |worker|
58
+ if worker.kind_of?(Worker) && worker.address_name == @address
59
+ ModernTimes.logger.debug "Dummy publishing #{object} to #{worker}"
60
+ worker.perform(object)
61
+ end
62
+ end
63
+ end
64
+
65
+ def self.setup_dummy_publishing(workers)
66
+ @@worker_instances = workers.map {|worker| worker.new}
67
+ alias_method :real_publish, :publish
68
+ alias_method :publish, :dummy_publish
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,19 @@
1
+ module ModernTimes
2
+ module HornetQ
3
+ class Supervisor < ModernTimes::Base::Supervisor
4
+ # Make HornetQ::SupervisorMBean our mbean
5
+ mbean SupervisorMBean
6
+
7
+ attr_reader :message_count
8
+
9
+ def initialize(manager, worker_name, opts={})
10
+ super(manager, worker_name, opts)
11
+ @message_count = 0
12
+ end
13
+
14
+ def incr_message_count
15
+ @message_count += 1
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,12 @@
1
+ module ModernTimes
2
+ module HornetQ
3
+ class SupervisorMBean < ModernTimes::Base::SupervisorMBean
4
+
5
+ operation 'Total message count'
6
+ returns :int
7
+ def message_count
8
+ supervisor.message_count
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,121 @@
1
+ module ModernTimes
2
+ module HornetQ
3
+
4
+ # Base Worker Class for any class that will be processing messages from queues
5
+ class Worker < ModernTimes::Base::Worker
6
+ # Default to ruby marshaling, but extenders can override as necessary
7
+ include MarshalStrategy::Ruby
8
+
9
+ # Make HornetQ::Supervisor our supervisor
10
+ supervisor Supervisor
11
+
12
+ attr_reader :session, :message_count
13
+
14
+ def initialize
15
+ @status = 'initialized'
16
+ @message_count = 0
17
+ end
18
+
19
+ def setup
20
+ session = Client.create_consumer_session
21
+ session.create_queue_ignore_exists(address_name, queue_name, false)
22
+ session.close
23
+ end
24
+
25
+ def status
26
+ @status || "Processing message #{message_count}"
27
+ end
28
+
29
+ def on_message(message)
30
+ object = unmarshal(message)
31
+ ModernTimes.logger.debug "#{self}: Received Object: #{object}" if ModernTimes.logger.debug?
32
+ perform(object)
33
+ ModernTimes.logger.debug "#{self}: Finished processing message" if ModernTimes.logger.debug?
34
+ ModernTimes.logger.flush if ModernTimes.logger.respond_to?(:flush)
35
+ rescue Exception => e
36
+ ModernTimes.logger.error "#{self}: Messaging Exception: #{e.inspect}\n#{e.backtrace.inspect}"
37
+ rescue java.lang.Exception => e
38
+ ModernTimes.logger.error "#{self}: Java Messaging Exception: #{e.inspect}\n#{e.backtrace.inspect}"
39
+ end
40
+
41
+ def perform(object)
42
+ raise "#{self}: Need to override perform method in #{self.class.name} in order to act on #{object}"
43
+ end
44
+
45
+ def self.address_name
46
+ @address_name ||= default_name
47
+ end
48
+
49
+ def self.queue_name
50
+ @queue_name ||= default_name
51
+ end
52
+
53
+ def address_name
54
+ self.class.address_name
55
+ end
56
+
57
+ def queue_name
58
+ self.class.queue_name
59
+ end
60
+
61
+ def to_s
62
+ "#{address_name}:#{queue_name}:#{index}"
63
+ end
64
+
65
+ # Start the event loop for handling messages off the queue
66
+ def start
67
+ @session = Client.create_consumer_session
68
+ @consumer = @session.create_consumer(queue_name)
69
+ @session.start
70
+ ModernTimes.logger.debug "#{self}: Starting receive loop"
71
+ @status = nil
72
+ while msg = @consumer.receive
73
+ @message_count += 1
74
+ supervisor.incr_message_count
75
+ on_message(msg)
76
+ msg.acknowledge
77
+ end
78
+ @status = 'Exited'
79
+ ModernTimes.logger.info "Exiting #{self}"
80
+ rescue Java::org.hornetq.api.core.HornetQException => e
81
+ if e.cause.code == Java::org.hornetq.api.core.HornetQException::OBJECT_CLOSED
82
+ # Normal exit
83
+ @status = 'Exited'
84
+ ModernTimes.logger.info "#{self}: Exiting due to close"
85
+ else
86
+ @status = "Exited with HornetQ exception #{e.message}"
87
+ ModernTImes.logger.error "#{self} HornetQException: #{e.message}\n#{e.backtrace.join("\n")}"
88
+ end
89
+ rescue Exception => e
90
+ @status = "Exited with exception #{e.message}"
91
+ ModernTimes.logger.error "#{self}: Exception, thread terminating: #{e.message}\n\t#{e.backtrace.join("\n\t")}"
92
+ rescue java.lang.Exception => e
93
+ @status = "Exited with java exception #{e.message}"
94
+ ModernTimes.logger.error "#{self}: Java exception, thread terminating: #{e.message}\n\t#{e.backtrace.join("\n\t")}"
95
+ end
96
+
97
+ def stop
98
+ @session.close if @session
99
+ end
100
+
101
+ #########
102
+ protected
103
+ #########
104
+
105
+ # Create a queue, assigned to the specified address
106
+ # Every time a message arrives, the perform instance method
107
+ # will be called. The parameter to the method is the Ruby
108
+ # object supplied when the message was sent
109
+ def self.address(address_name, opts={})
110
+ @address_name = address_name.to_s
111
+ #Messaging::Client.on_message(address, queue_name) do |object|
112
+ # self.send(method.to_sym, object)
113
+ #end
114
+ end
115
+
116
+ def self.queue(queue_name, opts={})
117
+ @queue_name = queue_name.to_s
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,11 @@
1
+ require 'modern_times/hornetq/client'
2
+ require 'modern_times/hornetq/marshal_strategy'
3
+ require 'modern_times/hornetq/publisher'
4
+ require 'modern_times/hornetq/supervisor_mbean'
5
+ require 'modern_times/hornetq/supervisor'
6
+ require 'modern_times/hornetq/worker'
7
+
8
+ module ModernTimes
9
+ module HornetQ
10
+ end
11
+ end
@@ -0,0 +1,23 @@
1
+ module ModernTimes
2
+ module Loggable
3
+ def logger
4
+ @logger ||= (rails_logger || default_logger)
5
+ end
6
+
7
+ def rails_logger
8
+ (defined?(Rails) && Rails.respond_to?(:logger) && Rails.logger) ||
9
+ (defined?(RAILS_DEFAULT_LOGGER) && RAILS_DEFAULT_LOGGER.respond_to?(:debug) && RAILS_DEFAULT_LOGGER)
10
+ end
11
+
12
+ def default_logger
13
+ require 'logger'
14
+ l = Logger.new($stdout)
15
+ l.level = Logger::INFO
16
+ l
17
+ end
18
+
19
+ def logger=(logger)
20
+ @logger = logger
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,92 @@
1
+ module ModernTimes
2
+ class Manager
3
+ attr_accessor :allowed_workers
4
+
5
+ def initialize(config={})
6
+ @config = config
7
+ @domain = config[:domain] || 'ModernTimes'
8
+ @supervisors = []
9
+ @jmx_server = JMX::MBeanServer.new
10
+ bean = ManagerMBean.new("#{@domain}.Manager", "Manager", self)
11
+ @jmx_server.register_mbean(bean, "#{@domain}:type=Manager")
12
+ persist_file = config[:persist_file]
13
+ end
14
+
15
+ def add(worker_klass, num_workers, worker_options)
16
+ ModernTimes.logger.info "Starting #{worker_klass} with #{num_workers} workers with options #{worker_options.inspect}"
17
+ unless worker_klass.kind_of?(Class)
18
+ begin
19
+ worker_klass = Object.const_get(worker_klass.to_s)
20
+ rescue
21
+ raise ModernTimes::Exception.new("Invalid class: #{worker_klass}")
22
+ end
23
+ end
24
+ if @allowed_workers && !@allowed_workers.include?(worker_klass)
25
+ raise ModernTimes::Exception.new("Error: #{worker_klass.name} is not an allowed worker")
26
+ end
27
+ supervisor = worker_klass.create_supervisor(self)
28
+ mbean = supervisor.create_mbean(@domain)
29
+ @supervisors << supervisor
30
+ supervisor.worker_count = num_workers
31
+ @jmx_server.register_mbean(mbean, "#{@domain}:worker=#{worker_klass.name},type=Worker")
32
+ ModernTimes.logger.info "Started #{worker_klass.name} with #{num_workers} workers"
33
+ rescue Exception => e
34
+ ModernTimes.logger.error "Exception trying to add #{worker_klass.name}: #{e.message}\n\t#{e.backtrace.join("\n\t")}"
35
+ rescue java.lang.Exception => e
36
+ ModernTimes.logger.error "Java exception trying to add #{worker_klass.name}: #{e.message}\n\t#{e.backtrace.join("\n\t")}"
37
+ end
38
+
39
+ def start
40
+ return if @started
41
+ @started = true
42
+
43
+ end
44
+
45
+ def stop
46
+ @stopped = true
47
+ @supervisors.each { |supervisor| supervisor.stop }
48
+ end
49
+
50
+ def join
51
+ while !@stopped
52
+ sleep 1
53
+ end
54
+ @supervisors.each { |supervisor| supervisor.join }
55
+ end
56
+
57
+ def stop_on_signal
58
+ ['HUP', 'INT', 'TERM'].each do |signal_name|
59
+ Signal.trap(signal_name) do
60
+ ModernTimes.logger.info "Caught #{signal_name}"
61
+ stop
62
+ end
63
+ end
64
+ end
65
+
66
+ def persist_file=(file)
67
+ @persist_file = file
68
+ return unless file
69
+ @persist_file = file
70
+ if File.exist?(file)
71
+ hash = YAML.load_file(file)
72
+ hash.each do |worker_klass, count|
73
+ add(worker_klass, count)
74
+ end
75
+ end
76
+ end
77
+
78
+ def save_persist_state
79
+ return unless @persist_file
80
+ hash = {}
81
+ @supervisors.each do |supervisor|
82
+ hash[supervisor.worker_name] = {
83
+ :worker_count => supervisor.worker_count,
84
+ :options => supervisor.worker_options
85
+ }
86
+ end
87
+ File.open(@persist_file, 'w') do |out|
88
+ YAML.dump(hash, out )
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,36 @@
1
+ require 'jmx'
2
+
3
+ module ModernTimes
4
+ class ManagerMBean < RubyDynamicMBean
5
+ attr_reader :manager
6
+ rw_attribute :foobar, :int, "Number of workers"
7
+
8
+ def initialize(name, description, manager)
9
+ super(name, description)
10
+ @manager = manager
11
+ end
12
+
13
+ operation 'Allowed workers'
14
+ returns :list
15
+ def allowed_workers
16
+ all = manager.allowed_workers || ['No Restrictions']
17
+ all.map {|worker_klass| worker_klass.name }
18
+ end
19
+
20
+ operation 'Start worker'
21
+ parameter :string, "worker", "The worker class to start"
22
+ parameter :int, "count", "Number of workers"
23
+ returns :string
24
+ def start_worker(worker, count)
25
+ ModernTimes.logger.debug "Attempting to start #{worker} with count=#{count}"
26
+ manager.add(worker, count)
27
+ return 'Successfuly started'
28
+ rescue Exception => e
29
+ ModernTimes.logger.error "Exception starting worker #{worker}: {e.message}\n\t#{e.backtrace.join("\n\t")}"
30
+ return "Exception starting worker #{worker}: {e.message}"
31
+ rescue java.lang.Exception => e
32
+ ModernTimes.logger.error "Java exception starting worker #{worker}: {e.message}\n\t#{e.backtrace.join("\n\t")}"
33
+ return "Java exception starting worker #{worker}: {e.message}"
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,132 @@
1
+ module ModernTimes
2
+ module Railsable
3
+ def init_rails
4
+ if cfg = YAML.load_file(File.join(Rails.root, "config", "hornetq.yml"))[Rails.env]
5
+ ModernTimes.logger.info "Messaging Enabled"
6
+ ModernTimes::HornetQ::Client.init(cfg)
7
+ @is_hornetq_enabled = true
8
+
9
+ # Need to start the HornetQ Server in this VM
10
+ if ModernTimes::HornetQ::Client.invm?
11
+ @server = ::HornetQ::Server.create_server('hornetq://invm')
12
+ @server.start
13
+
14
+ # Handle messages within this process
15
+ @manager = ModernTimes::Manager.new
16
+ if worker_cfg = cfg[:workers]
17
+ worker_cfg.each do |klass, count|
18
+ @manager.add(klass, count)
19
+ end
20
+ else
21
+ rails_workers.each do |klass|
22
+ @manager.add(klass, 1)
23
+ end
24
+ end
25
+
26
+ at_exit do
27
+ @manager.stop if @manager
28
+ @server.stop
29
+ end
30
+ end
31
+
32
+ # Create Async Queue and handle requests
33
+ #self.async_queue_name = self.async_address = "Messaging::Client.async"
34
+ #self.on_message(self.async_address, self.async_queue_name) do |request|
35
+ # self.async_on_message(request)
36
+ #end
37
+
38
+ else
39
+ Rails.logger.info "Messaging disabled"
40
+ @is_hornetq_enabled = false
41
+ ModernTimes::HornetQ::Publisher.setup_dummy_publishing(rails_workers)
42
+ end
43
+ end
44
+
45
+ def create_rails_manager
46
+ cfg = YAML.load_file(File.join(Rails.root, "config", "hornetq.yml"))[Rails.env]
47
+ raise "No valid configuration" unless cfg
48
+ ModernTimes::HornetQ::Client.init(cfg)
49
+
50
+ manager = ModernTimes::Manager.new
51
+ manager.stop_on_signal
52
+ manager.allowed_workers = rails_workers
53
+ manager.persist_file = cfg[:persist_file] || File.join(Rails.root, "log", "modern_times.persist")
54
+ return manager
55
+ end
56
+
57
+ def rails_workers
58
+ @rails_workers ||= begin
59
+ workers = []
60
+ Dir["#{Rails.root}/app/workers/*_worker.rb"].each do |file|
61
+ require file
62
+ workers << File.basename(file).sub(/\.rb$/, '').classify.constantize
63
+ end
64
+ workers
65
+ end
66
+ #file = "#{Rails.root}/config/workers.yml"
67
+ #raise "No worker config file #{file}" unless File.exist?(file)
68
+ end
69
+
70
+ def hornetq_enabled?
71
+ @is_hornetq_enabled
72
+ end
73
+ end
74
+ end
75
+
76
+
77
+ ## Protocol independent class to handle Messaging and Queuing
78
+ #module Messaging
79
+ # class Client
80
+ #
81
+ # # Publish to the specified address
82
+ # # If the supplied object is kind_of? String, then a string is published
83
+ # # Otherwise the Ruby Object is unmarshaled and sent as a Binary message
84
+ #
85
+ # # Asynchronously invoke the supplied method
86
+ # #
87
+ # # Example:
88
+ # # Messaging::Client.async(Dashboard, :update_dashboard_for_inquiry, xml_response)
89
+ # def self.async(klass, method, *param)
90
+ # @@session_pool.producer(self.async_address) do |session, producer|
91
+ # request = AsyncRequest.new
92
+ # request.klass = if klass.kind_of?(String)
93
+ # klass
94
+ # elsif klass.kind_of?(Symbol)
95
+ # klass.to_s
96
+ # else
97
+ # klass.name.to_s
98
+ # end
99
+ # request.method = method
100
+ # request.params = *param
101
+ # message = session.create_message(4,false) #HornetQ::Client::Message::BYTES_TYPE
102
+ # message['format'] = 'ruby'
103
+ # message.body = Marshal.dump(request)
104
+ # producer.send(message)
105
+ # end
106
+ # end
107
+ #
108
+ # private
109
+ # # Call the specified class passing in the required parameters
110
+ # # If the method matches a class method, it is called, otherwise
111
+ # # an instance of the class is created and the method is called
112
+ # # on the new instance
113
+ # #
114
+ # # Note: Instance methods are more expensive because the class is instantiated
115
+ # # for every call
116
+ # def self.async_on_message(request)
117
+ # klass = request.klass.constantize
118
+ # method = request.method.to_sym
119
+ # if klass.respond_to?(method, false)
120
+ # klass.send(method, *request.params)
121
+ # else
122
+ # klass.new.send(method, *request.params)
123
+ # end
124
+ # end
125
+ #
126
+ # # Passed as the request message, used to hold all required parameters
127
+ # class AsyncRequest
128
+ # attr_accessor :klass, :method, :params
129
+ # end
130
+ #
131
+ # end
132
+ #end
@@ -0,0 +1,16 @@
1
+ module ModernTimes
2
+ class Thread < ::Thread
3
+ def initialize(&block)
4
+ super() do
5
+ begin
6
+ yield
7
+ rescue => e
8
+ ModernTimes.logger.fatal("Thread #{self} died due to exception #{e.message}\n#{e.backtrace.join("\n")}")
9
+ ensure
10
+ ActiveRecord::Base.clear_active_connections!() if Module.const_get('ActiveRecord') rescue nil
11
+ ModernTimes.logger.flush if ModernTimes.logger.respond_to?(:flush)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,13 @@
1
+ require 'rubygems'
2
+ require 'modern_times/exception'
3
+ require 'modern_times/base'
4
+ require 'modern_times/hornetq'
5
+ require 'modern_times/manager_mbean'
6
+ require 'modern_times/manager'
7
+ require 'modern_times/loggable'
8
+ require 'modern_times/railsable'
9
+
10
+ module ModernTimes
11
+ extend ModernTimes::Loggable
12
+ extend ModernTimes::Railsable
13
+ end