modern_times 0.1.0

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 (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