modern_times 0.1.2 → 0.2.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 (64) hide show
  1. data/README.rdoc +24 -12
  2. data/Rakefile +2 -2
  3. data/VERSION +1 -1
  4. data/examples/README +4 -0
  5. data/examples/jms.yml +9 -0
  6. data/examples/requestor/README +4 -2
  7. data/examples/requestor/manager.rb +3 -2
  8. data/examples/requestor/request.rb +5 -4
  9. data/examples/requestor/reverse_echo_worker.rb +3 -2
  10. data/examples/simple/README +7 -4
  11. data/examples/simple/bar_worker.rb +4 -1
  12. data/examples/simple/baz_worker.rb +4 -3
  13. data/examples/simple/manager.rb +3 -2
  14. data/examples/simple/publish.rb +6 -5
  15. data/lib/modern_times.rb +20 -2
  16. data/lib/modern_times/base/supervisor.rb +14 -21
  17. data/lib/modern_times/base/supervisor_mbean.rb +4 -6
  18. data/lib/modern_times/base/worker.rb +17 -26
  19. data/lib/modern_times/jms.rb +23 -0
  20. data/lib/modern_times/{hornetq/client.rb → jms/connection.rb} +19 -12
  21. data/lib/modern_times/jms/publisher.rb +91 -0
  22. data/lib/modern_times/jms/supervisor.rb +19 -0
  23. data/lib/modern_times/jms/supervisor_mbean.rb +11 -0
  24. data/lib/modern_times/jms/worker.rb +166 -0
  25. data/lib/modern_times/jms_requestor.rb +10 -0
  26. data/lib/modern_times/jms_requestor/request_handle.rb +33 -0
  27. data/lib/modern_times/jms_requestor/requestor.rb +45 -0
  28. data/lib/modern_times/jms_requestor/supervisor.rb +45 -0
  29. data/lib/modern_times/jms_requestor/supervisor_mbean.rb +21 -0
  30. data/lib/modern_times/jms_requestor/worker.rb +78 -0
  31. data/lib/modern_times/manager.rb +14 -9
  32. data/lib/modern_times/manager_mbean.rb +14 -7
  33. data/lib/modern_times/marshal_strategy.rb +47 -0
  34. data/lib/modern_times/marshal_strategy/bson.rb +31 -0
  35. data/lib/modern_times/marshal_strategy/json.rb +30 -0
  36. data/lib/modern_times/marshal_strategy/ruby.rb +20 -0
  37. data/lib/modern_times/marshal_strategy/string.rb +19 -0
  38. data/lib/modern_times/railsable.rb +17 -74
  39. data/test/base_test.rb +248 -0
  40. data/test/jms.yml +8 -0
  41. data/test/jms_requestor_test.rb +263 -0
  42. data/test/jms_test.rb +296 -0
  43. data/test/marshal_strategy_test.rb +39 -0
  44. metadata +49 -46
  45. data/examples/requestor/hornetq.yml +0 -14
  46. data/examples/simple/hornetq.yml +0 -14
  47. data/lib/modern_times/hornetq.rb +0 -11
  48. data/lib/modern_times/hornetq/marshal_strategy.rb +0 -3
  49. data/lib/modern_times/hornetq/marshal_strategy/json.rb +0 -17
  50. data/lib/modern_times/hornetq/marshal_strategy/ruby.rb +0 -17
  51. data/lib/modern_times/hornetq/marshal_strategy/string.rb +0 -17
  52. data/lib/modern_times/hornetq/publisher.rb +0 -65
  53. data/lib/modern_times/hornetq/supervisor.rb +0 -22
  54. data/lib/modern_times/hornetq/supervisor_mbean.rb +0 -12
  55. data/lib/modern_times/hornetq/worker.rb +0 -127
  56. data/lib/modern_times/hornetq_requestor.rb +0 -9
  57. data/lib/modern_times/hornetq_requestor/request_handle.rb +0 -49
  58. data/lib/modern_times/hornetq_requestor/requestor.rb +0 -48
  59. data/lib/modern_times/hornetq_requestor/worker.rb +0 -29
  60. data/lib/modern_times/thread.rb +0 -16
  61. data/test/base/worker_test.rb +0 -38
  62. data/test/messaging/worker_manager_test.rb +0 -58
  63. data/test/messaging/worker_test.rb +0 -58
  64. data/test/worker_manager_test.rb +0 -48
data/README.rdoc CHANGED
@@ -4,11 +4,20 @@
4
4
 
5
5
  == Description:
6
6
 
7
- JRuby library for performing background tasks via the hornetq messaging library.
7
+ JRuby library for performing background tasks via JMS.
8
+
9
+ Very much alpha stage at this point.
8
10
 
9
11
  == Features/Problems:
10
12
 
11
- * TBD
13
+ * Ruby marshaling doesn't work
14
+ * jms_test doesn't exit
15
+ * jms_requestor needs testing for dummy requesting
16
+ * Allow options (durable queues, etc)
17
+ * Railsable needs testing
18
+ * Fail options (fail queues, etc.)
19
+ * Return exception for jms_requestor
20
+ * Currently tested only for ActiveMQ
12
21
 
13
22
  == Install:
14
23
 
@@ -16,27 +25,30 @@ JRuby library for performing background tasks via the hornetq messaging library.
16
25
 
17
26
  == Rails Usage:
18
27
 
19
- Create config/hornetq.yml which might look as follows:
28
+ TODO: This section needs updating for JMS
29
+
30
+ Create config/jms.yml which might look as follows:
20
31
 
21
32
  development:
22
33
  :connection: hornetq://invm
23
34
 
24
35
  production:
25
36
  :connection:
26
- :uri: hornetq://msg1,msg2
27
- :failover_on_initial_connection: true
28
- :failover_on_server_shutdown: true
29
- # 5 Connection attempts takes about 16 seconds before it switches to the backup server
30
- :reconnect_attempts: 5
37
+ :factory: org.apache.activemq.ActiveMQConnectionFactory
38
+ :broker_url: tcp://msghost:61616
39
+ :require_jars:
40
+ - <%= Dir.glob("#{ENV['ACTIVEMQ_HOME']}/activemq-all-*.jar")[0] %>
41
+ - <%= Dir.glob("#{ENV['ACTIVEMQ_HOME']}/lib/optional/slf4j-log4j*.jar")[0] %>
42
+ - <%= Dir.glob("#{ENV['ACTIVEMQ_HOME']}/lib/optional/log4j-*.jar")[0] %>
31
43
  :session:
32
- :username: mycluster_username
33
- :password: mycluster_password
44
+ :username: myuser
45
+ :password: mypassword
34
46
 
35
47
  In config/environment.rb, add the following lines:
36
48
 
37
49
  ModernTimes.init_rails
38
50
  # Publishers can be defined wherever appropriate
39
- $foo_publisher = ModernTimes::HornetQ::Publisher.new('Foo')
51
+ $foo_publisher = ModernTimes::JMS::Publisher.new('Foo')
40
52
 
41
53
  In your code, queue foo objects:
42
54
 
@@ -136,7 +148,7 @@ I'm a Chaplin fan.
136
148
 
137
149
  == Author
138
150
 
139
- Brad Pardee, Reid Morrison
151
+ Brad Pardee
140
152
 
141
153
  == Copyright
142
154
 
data/Rakefile CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'rubygems'
2
2
  require 'rake'
3
+ require 'rake/testtask'
3
4
 
4
5
  begin
5
6
  require 'jeweler'
@@ -10,9 +11,8 @@ begin
10
11
  gemspec.authors = ['Brad Pardee', 'Reid Morrison']
11
12
  gemspec.email = ['bradpardee@gmail.com', 'rubywmq@gmail.com']
12
13
  gemspec.homepage = 'http://github.com/ClarityServices/modern_times'
13
- gemspec.add_dependency 'jruby-hornetq', ['>= 0.3.3']
14
+ gemspec.add_dependency 'jruby-jms', ['>= 0.11.0']
14
15
  gemspec.add_dependency 'jmx', ['>= 0.6']
15
- gemspec.add_dependency 'json'
16
16
  end
17
17
  rescue LoadError
18
18
  puts 'Jeweler not available. Install it with: gem install jeweler'
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.2
1
+ 0.2.0
data/examples/README ADDED
@@ -0,0 +1,4 @@
1
+ In order to run the examples, you might need to modify the jms.yml file
2
+ in this directory. Also, you may have to set the enviroment variable
3
+ ACTIVEMQ_HOME in order to run with no jms.yml file changes. Refer to
4
+ the jruby-jms project for more options for the jms.yml file.
data/examples/jms.yml ADDED
@@ -0,0 +1,9 @@
1
+ :factory: org.apache.activemq.ActiveMQConnectionFactory
2
+ :broker_url: tcp://localhost:61616
3
+ :require_jars:
4
+ - <%= Dir.glob("#{ENV['ACTIVEMQ_HOME']}/activemq-all-*.jar")[0] %>
5
+ #Uncomment the following for 5.5 version
6
+ #- <%= Dir.glob("#{ENV['ACTIVEMQ_HOME']}/lib/optional/slf4j-log4j*.jar")[0] %>
7
+ #- <%= Dir.glob("#{ENV['ACTIVEMQ_HOME']}/lib/optional/log4j-*.jar")[0] %>
8
+ #:username: myuser
9
+ #:password: mypassword
@@ -1,6 +1,8 @@
1
+ # Step 0
2
+ # Follow the directions for configuring jms.yml located in examples/README
3
+
1
4
  # Step 1
2
- # Start a hornetq server (gem install jruby-hornetq if necessary)
3
- hornetq_server hornetq.yml server
5
+ # Start an ActiveMQ Server
4
6
 
5
7
  # Step 2
6
8
  # Start up the manager
@@ -2,12 +2,13 @@
2
2
  $LOAD_PATH.unshift File.dirname(__FILE__) + '/../../lib'
3
3
 
4
4
  require 'rubygems'
5
+ require 'erb'
5
6
  require 'modern_times'
6
7
  require 'yaml'
7
8
  require 'reverse_echo_worker'
8
9
 
9
- config = YAML.load_file('hornetq.yml')
10
- ModernTimes::HornetQ::Client.init(config['client'])
10
+ config = YAML.load(ERB.new(File.read(File.join(File.dirname(__FILE__), '..', 'jms.yml'))).result(binding))
11
+ ModernTimes::JMS::Connection.init(config)
11
12
 
12
13
  manager = ModernTimes::Manager.new
13
14
  manager.stop_on_signal
@@ -2,6 +2,7 @@
2
2
  $LOAD_PATH.unshift File.dirname(__FILE__) + '/../../lib'
3
3
 
4
4
  require 'rubygems'
5
+ require 'erb'
5
6
  require 'modern_times'
6
7
  require 'yaml'
7
8
  require 'reverse_echo_worker'
@@ -16,9 +17,9 @@ $timeout = (ARGV[1] || 4).to_f
16
17
  $sleep_time = (ARGV[2] || 2).to_i
17
18
  $sim_count = (ARGV[3] || 1).to_i
18
19
 
19
- config = YAML.load_file('hornetq.yml')
20
- ModernTimes::HornetQ::Client.init(config['client'])
21
- $requestor = ModernTimes::HornetQRequestor::Requestor.new(ReverseEchoWorker.address_name, :marshal => :string)
20
+ config = YAML.load(ERB.new(File.read(File.join(File.dirname(__FILE__), '..', 'jms.yml'))).result(binding))
21
+ ModernTimes::JMS::Connection.init(config)
22
+ $requestor = ModernTimes::JMSRequestor::Requestor.new(:queue_name => ReverseEchoWorker.default_name, :marshal => :string)
22
23
 
23
24
  def make_request(ident='')
24
25
  puts "#{ident}Making request at #{Time.now.to_f}"
@@ -29,7 +30,7 @@ def make_request(ident='')
29
30
  response = handle.read_response
30
31
  puts "#{ident}Received at #{Time.now.to_f}: #{response}"
31
32
  rescue Exception => e
32
- puts "#{ident}Exception: #{e.message}"
33
+ puts "#{ident}Exception: #{e.message}\n\t#{e.backtrace.join("\n\t")}"
33
34
  end
34
35
 
35
36
  if $sim_count == 1
@@ -1,5 +1,6 @@
1
- class ReverseEchoWorker < ModernTimes::HornetQRequestor::Worker
2
- include ModernTimes::HornetQ::MarshalStrategy::String
1
+ class ReverseEchoWorker
2
+ include ModernTimes::JMSRequestor::Worker
3
+ marshal :string
3
4
 
4
5
  def request(obj)
5
6
  puts "#{self}: Received #{obj} at #{Time.now}"
@@ -1,9 +1,12 @@
1
+ # Step 0
2
+ # Follow the directions for configuring jms.yml located in examples/README
3
+
1
4
  # Step 1
2
- # Start a hornetq server (gem install jruby-hornetq if necessary)
3
- hornetq_server hornetq.yml server
5
+ # Start a JMS Server
4
6
 
5
7
  # Step 2
6
8
  # Start up the manager
9
+ rm -f modern_times.state
7
10
  jruby manager.rb
8
11
 
9
12
  # Step 3
@@ -11,8 +14,8 @@ jruby manager.rb
11
14
  # Attach to the manager process
12
15
  # Go to the MBeans tab
13
16
  # Open up the tree to ModernTimes => Manager => Operations => start_worker
14
- # Enter BarWorker for worker and 2 for count and click the start_worker button
15
- # Enter BazWorker for worker and 3 for count and click the start_worker button
17
+ # Enter BarWorker for worker, 2 for count, clear the options field, and click the start_worker button.
18
+ # Enter BazWorker for worker, 3 for count, clear the options field, and click the start_worker button.
16
19
 
17
20
  # Step 4
18
21
  # Publish 10 messages to the BarWorker and 20 to the BazWorker
@@ -1,4 +1,7 @@
1
- class BarWorker < ModernTimes::HornetQ::Worker
1
+ class BarWorker
2
+ include ModernTimes::JMS::Worker
3
+ marshal :bson
4
+
2
5
  def perform(obj)
3
6
  puts "#{self}: Received #{obj.inspect} at #{Time.now}"
4
7
  sleep 5
@@ -1,6 +1,7 @@
1
- class BazWorker < ModernTimes::HornetQ::Worker
2
- include ModernTimes::HornetQ::MarshalStrategy::String
3
-
1
+ class BazWorker
2
+ include ModernTimes::JMS::Worker
3
+ marshal :string
4
+
4
5
  def perform(obj)
5
6
  puts "#{self}: Received #{obj} at #{Time.now}"
6
7
  sleep 10
@@ -2,13 +2,14 @@
2
2
  $LOAD_PATH.unshift File.dirname(__FILE__) + '/../../lib'
3
3
 
4
4
  require 'rubygems'
5
+ require 'erb'
5
6
  require 'modern_times'
6
7
  require 'yaml'
7
8
  require 'bar_worker'
8
9
  require 'baz_worker'
9
10
 
10
- config = YAML.load_file('hornetq.yml')
11
- ModernTimes::HornetQ::Client.init(config['client'])
11
+ config = YAML.load(ERB.new(File.read(File.join(File.dirname(__FILE__), '..', 'jms.yml'))).result(binding))
12
+ ModernTimes::JMS::Connection.init(config)
12
13
 
13
14
  manager = ModernTimes::Manager.new(:persist_file => 'modern_times.state')
14
15
  manager.stop_on_signal
@@ -2,6 +2,7 @@
2
2
  $LOAD_PATH.unshift File.dirname(__FILE__) + '/../../lib'
3
3
 
4
4
  require 'rubygems'
5
+ require 'erb'
5
6
  require 'modern_times'
6
7
  require 'yaml'
7
8
  require 'bar_worker'
@@ -15,13 +16,13 @@ bar_count = ARGV[0].to_i
15
16
  baz_count = ARGV[1].to_i
16
17
  sleep_time = (ARGV[2] || 0.2).to_f
17
18
 
18
- config = YAML.load_file('hornetq.yml')
19
- ModernTimes::HornetQ::Client.init(config['client'])
20
- bar_publisher = ModernTimes::HornetQ::Publisher.new(BarWorker.address_name)
21
- baz_publisher = ModernTimes::HornetQ::Publisher.new(BazWorker.address_name, :marshal => :string)
19
+ config = YAML.load(ERB.new(File.read(File.join(File.dirname(__FILE__), '..', 'jms.yml'))).result(binding))
20
+ ModernTimes::JMS::Connection.init(config)
21
+ bar_publisher = ModernTimes::JMS::Publisher.new(:queue_name => 'Bar', :marshal => :bson)
22
+ baz_publisher = ModernTimes::JMS::Publisher.new(:queue_name => 'Baz', :marshal => :string)
22
23
 
23
24
  (1..bar_count).each do |i|
24
- obj = {:message => i}
25
+ obj = {'message' => i}
25
26
  puts "Publishing to Bar object: #{obj.inspect}"
26
27
  bar_publisher.publish(obj)
27
28
  sleep sleep_time
data/lib/modern_times.rb CHANGED
@@ -1,8 +1,9 @@
1
1
  require 'rubygems'
2
2
  require 'modern_times/exception'
3
+ require 'modern_times/marshal_strategy'
3
4
  require 'modern_times/base'
4
- require 'modern_times/hornetq'
5
- require 'modern_times/hornetq_requestor'
5
+ require 'modern_times/jms'
6
+ require 'modern_times/jms_requestor'
6
7
  require 'modern_times/manager_mbean'
7
8
  require 'modern_times/manager'
8
9
  require 'modern_times/loggable'
@@ -11,4 +12,21 @@ require 'modern_times/railsable'
11
12
  module ModernTimes
12
13
  extend ModernTimes::Loggable
13
14
  extend ModernTimes::Railsable
15
+
16
+ DEFAULT_DOMAIN = 'ModernTimes'
17
+
18
+ def self.manager_mbean_name(domain)
19
+ domain = DEFAULT_DOMAIN unless domain
20
+ "#{domain}.Manager"
21
+ end
22
+
23
+ def self.manager_mbean_object_name(domain)
24
+ domain = DEFAULT_DOMAIN unless domain
25
+ "#{domain}:type=Manager"
26
+ end
27
+
28
+ def self.supervisor_mbean_object_name(domain, worker_name)
29
+ domain = DEFAULT_DOMAIN unless domain
30
+ "#{domain}:worker=#{worker_name},type=Worker"
31
+ end
14
32
  end
@@ -1,7 +1,7 @@
1
1
  module ModernTimes
2
2
  module Base
3
3
  class Supervisor
4
- attr_reader :manager, :worker_klass, :name, :worker_options
4
+ attr_reader :manager, :worker_klass, :name, :worker_options, :workers
5
5
 
6
6
  # Create new supervisor to manage a number of similar workers
7
7
  # supervisor_options are those options defined on the Worker's Supervisor line
@@ -10,7 +10,7 @@ module ModernTimes
10
10
  @stopped = false
11
11
  @manager = manager
12
12
  @worker_klass = worker_klass
13
- @name = worker_options.delete(:name) || worker_klass.default_name
13
+ @name = worker_options[:name] || worker_klass.default_name
14
14
  @worker_options = worker_options
15
15
  @workers = []
16
16
  @worker_mutex = Mutex.new
@@ -29,14 +29,13 @@ module ModernTimes
29
29
  if curr_count < count
30
30
  (curr_count...count).each do |index|
31
31
  worker = @worker_klass.new(@worker_options)
32
- worker.supervisor = self
33
32
  worker.index = index
34
33
  if index == 0
35
34
  # HornetQ hack: If I create the session in the jmx thread, it dies with no feedback
36
- tmp_thread = Thread.new do
35
+ #tmp_thread = Thread.new do
37
36
  worker.setup
38
- end
39
- tmp_thread.join
37
+ #end
38
+ #tmp_thread.join
40
39
  end
41
40
  worker.thread = Thread.new do
42
41
  #ModernTimes.logger.debug "#{worker}: Started thread with priority #{Thread.current.priority}"
@@ -53,8 +52,8 @@ module ModernTimes
53
52
  end
54
53
  end
55
54
 
56
- def worker_status(index)
57
- @workers[index].status
55
+ def worker_statuses
56
+ @workers.map { |w| w.status }
58
57
  end
59
58
 
60
59
  def stop
@@ -76,22 +75,16 @@ module ModernTimes
76
75
 
77
76
  end
78
77
 
79
- def self.mbean(klass, options={})
80
- # self.class.class_eval do
81
- # define_method :create_mbean do |domain, supervisor, worker_klass|
82
- # klass.new("#{domain}.Worker.#{worker_klass.name}", "Supervisor for #{worker_klass.name}", supervisor, options)
83
- # end
84
- # end
85
- # TODO: This is nasty but I'm not sure how to create a dynamic class method within a scope
86
- eval <<-EOS
87
- def self.create_mbean(domain, supervisor, worker_klass)
88
- #{klass.name}.new("\#{domain}.Worker.\#{worker_klass.name}", "Supervisor for \#{worker_klass.name}", supervisor, #{options.inspect})
89
- end
90
- EOS
78
+ def mbean_name(domain)
79
+ "#{domain}.Worker.#{@name}"
80
+ end
81
+
82
+ def mbean_description
83
+ "Supervisor for #{@worker_klass.name} under #{@name}"
91
84
  end
92
85
 
93
86
  def create_mbean(domain)
94
- self.class.create_mbean(domain, self, @worker_klass)
87
+ SupervisorMBean.new(mbean_name(domain), mbean_description, self, {})
95
88
  end
96
89
 
97
90
  #########
@@ -3,8 +3,9 @@ require 'jmx'
3
3
  module ModernTimes
4
4
  module Base
5
5
  class SupervisorMBean < RubyDynamicMBean
6
- attr_reader :supervisor
6
+ attr_reader :supervisor
7
7
  rw_attribute :worker_count, :int, "Number of workers"
8
+ r_attribute :worker_statuses, :list, 'Status of the workers'
8
9
 
9
10
  def initialize(name, description, supervisor, options)
10
11
  super(name, description)
@@ -19,11 +20,8 @@ module ModernTimes
19
20
  supervisor.worker_count = count
20
21
  end
21
22
 
22
- operation 'Get the worker status'
23
- parameter :int, "index", "Index of the worker"
24
- returns :string
25
- def worker_status(index)
26
- supervisor.worker_status(index)
23
+ def worker_statuses
24
+ java.util.ArrayList.new(supervisor.worker_statuses)
27
25
  end
28
26
  end
29
27
  end
@@ -1,36 +1,32 @@
1
- require 'json'
2
-
3
1
  module ModernTimes
4
2
  module Base
5
- class Worker
6
- attr_accessor :index, :supervisor, :thread
7
-
8
- def self.supervisor(klass, options={})
9
- # self.class_eval do
10
- # define_method :create_supervisor do |manager|
11
- # puts "calling create_supervisor for klass-#{klass.name} and self=#{self} and manager=#{manager}"
12
- # klass.new(manager, self, options)
13
- # end
14
- # end
15
- # TODO: This is nasty but I'm not sure how to create a dynamic class method within a scope
16
- eval <<-EOS
17
- def self.create_supervisor(manager, worker_options)
18
- #{klass.name}.new(manager, self, #{options.to_json}, worker_options)
19
- end
20
- EOS
3
+ module Worker
4
+ attr_accessor :name, :index, :thread
5
+
6
+ module ClassMethods
7
+ def default_name
8
+ name = self.name.sub(/Worker$/, '')
9
+ name.sub(/::/, '_')
10
+ end
11
+
12
+ def create_supervisor(manager, worker_options)
13
+ Supervisor.new(manager, self, {}, worker_options)
14
+ end
21
15
  end
22
16
 
23
- # Default supervisor is Base::Supervisor
24
- supervisor Supervisor
17
+ def self.included(base)
18
+ base.extend(ClassMethods)
19
+ end
25
20
 
26
21
  def initialize(opts={})
22
+ @name = opts[:name] || self.class.default_name
27
23
  end
28
24
 
29
25
  # One time initialization prior to first thread
30
26
  def setup
31
27
  end
32
28
 
33
- def start
29
+ def start(name)
34
30
  raise "Need to override start method in #{self.class.name}"
35
31
  end
36
32
 
@@ -41,11 +37,6 @@ module ModernTimes
41
37
  def status
42
38
  raise "Need to override status method in #{self.class.name}"
43
39
  end
44
-
45
- def self.default_name
46
- name = self.name.sub(/Worker$/, '')
47
- name.sub(/::/, '_')
48
- end
49
40
  end
50
41
  end
51
42
  end