modern_times 0.1.2 → 0.2.0

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