modern_times 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
data/History.md ADDED
@@ -0,0 +1,9 @@
1
+ ModernTimes Changelog
2
+ =====================
3
+
4
+ 0.3.2 (pending)
5
+ -----
6
+
7
+ - Bug fixes
8
+ - Allow response options like time_to_live and persistence in publisher
9
+
data/README.rdoc CHANGED
@@ -10,9 +10,6 @@ Still alpha but approaching beta. API still subject to change.
10
10
 
11
11
  == Features/Problems:
12
12
 
13
- * jms_test and jms_requestor_test don't exit
14
- * Railsable needs testing
15
- * failure_queue needs testing
16
13
  * Currently tested only for ActiveMQ
17
14
 
18
15
  == Install:
@@ -21,8 +18,6 @@ Still alpha but approaching beta. API still subject to change.
21
18
 
22
19
  == Rails Usage:
23
20
 
24
- TODO: This section needs updating for JMS
25
-
26
21
  Create config/jms.yml which might look as follows:
27
22
 
28
23
  development_server: &defaults
@@ -40,13 +35,13 @@ Create config/jms.yml which might look as follows:
40
35
  <<: *defaults
41
36
  :broker_url: tcp://stage2:61616
42
37
  :username: myuser
43
- :password: <%=Encryption.try_decrypt "fadsfdasfdsfdasfdsafas" %>
38
+ :password: mypassword
44
39
 
45
40
  production:
46
41
  <<: *defaults
47
- :broker_url: failover://(tcp://msg1:61616,tcp://msg2:61616)?randomize=false&timeout=60000&initialReconnectDelay=100&useExponentialBackOff=true
42
+ :broker_url: failover://(tcp://msg1:61616,tcp://msg2:61616)?randomize=false&initialReconnectDelay=100&useExponentialBackOff=true&maxCacheSize=524288&trackMessages=true
48
43
  :username: myuser
49
- :password: <%=Encryption.try_decrypt "afsadsfasdfa/afasdfdasf\n" %>
44
+ :password: mypassword
50
45
 
51
46
  In development and test mode, you will notice that there is no configuration defined. In this case, published messages will cause
52
47
  synchronous calls to the Worker's perform method which matches the destination queue or topic.
data/TODO.md ADDED
@@ -0,0 +1,10 @@
1
+ TODO
2
+ ========
3
+
4
+ * jms/consumer.rb - is it needed? is dummy stuff needed?
5
+ * Better API documentation
6
+ * jms_test and jms_requestor_test don't exit
7
+ * Responses aren't non-persistent? Why are timed out responses ending up in the DLQ?
8
+ * RequestWorker needs option for failure queue as well as sending exception in response
9
+ * Batch file handling coming soon
10
+ * More thorough test coverage, especially the various options, Railsable, etc.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.1
1
+ 0.3.2
@@ -1,2 +1,2 @@
1
1
  data
2
- *.state
2
+ modern_times.yml
@@ -1,12 +1,13 @@
1
1
  # Step 0
2
2
  # Follow the directions for configuring jms.yml located in examples/README
3
+ # Perform steps 1-4 in separate terminals
3
4
 
4
5
  # Step 1
5
6
  # Start a JMS Server
6
7
 
7
8
  # Step 2
8
9
  # Start up the manager
9
- rm -f modern_times.state
10
+ rm -f modern_times.yml
10
11
  jruby manager.rb
11
12
 
12
13
  # Step 3
@@ -18,7 +19,7 @@ jruby manager.rb
18
19
  # Enter BazWorker for worker, 3 for count, clear the options field, and click the start_worker button.
19
20
 
20
21
  # Step 4
21
- # Publish 10 messages to the BarWorker and 20 to the BazWorker
22
+ # Publish 10 messages to the BarWorker and 5 to the BazWorker
22
23
  jruby publish.rb 10 5
23
24
 
24
25
  # Step 5
@@ -1,6 +1,5 @@
1
1
  class BarWorker
2
2
  include ModernTimes::JMS::Worker
3
- marshal :bson
4
3
 
5
4
  def perform(obj)
6
5
  puts "#{self}: Received #{obj.inspect} at #{Time.now}"
@@ -1,6 +1,5 @@
1
1
  class BazWorker
2
2
  include ModernTimes::JMS::Worker
3
- marshal :string
4
3
 
5
4
  def perform(obj)
6
5
  puts "#{self}: Received #{obj} at #{Time.now}"
@@ -11,7 +11,7 @@ require 'baz_worker'
11
11
  config = YAML.load(ERB.new(File.read(File.join(File.dirname(__FILE__), '..', 'jms.yml'))).result(binding))
12
12
  ModernTimes::JMS::Connection.init(config)
13
13
 
14
- manager = ModernTimes::Manager.new(:persist_file => 'modern_times.state')
14
+ manager = ModernTimes::Manager.new(:persist_file => 'modern_times.yml')
15
15
  manager.stop_on_signal
16
16
  manager.allowed_workers = [BarWorker,BazWorker]
17
17
  #manager.add(BarWorker, 2, {})
@@ -14,7 +14,6 @@ module ModernTimes
14
14
  @worker_options = worker_options
15
15
  @workers = []
16
16
  @worker_mutex = Mutex.new
17
- @failure_mutex = Mutex.new
18
17
  end
19
18
 
20
19
  def worker_count
@@ -70,11 +69,7 @@ module ModernTimes
70
69
  end
71
70
 
72
71
  def join
73
- @workers.each { |worker| worker.thread.join }
74
- end
75
-
76
- def failure(worker, message)
77
-
72
+ @workers.each { |worker| worker.join }
78
73
  end
79
74
 
80
75
  def mbean_name(domain)
@@ -36,6 +36,10 @@ module ModernTimes
36
36
  raise "Need to override stop method in #{self.class.name}"
37
37
  end
38
38
 
39
+ def join
40
+ thread.join
41
+ end
42
+
39
43
  def status
40
44
  raise "Need to override status method in #{self.class.name}"
41
45
  end
@@ -63,7 +63,7 @@ module ModernTimes
63
63
  end
64
64
 
65
65
  def dummy_read_response(timeout, &block)
66
- raise "Invalid call to read_response for #{@publisher}, not setup for responding" unless @publisher.response
66
+ raise "Invalid call to read_response for #{@publisher}, not setup for responding" unless @publisher.response?
67
67
  do_read_response(nil, timeout, &block)
68
68
  end
69
69
 
@@ -183,11 +183,11 @@ module ModernTimes
183
183
  message = consumer.receive(100)
184
184
  end
185
185
  return nil unless message
186
- @name = message['worker']
187
- if error_yaml = message['exception']
186
+ @name = message['mt:worker']
187
+ if error_yaml = message['mt:exception']
188
188
  return ModernTimes::RemoteException.from_hash(YAML.load(error_yaml))
189
189
  end
190
- marshaler = ModernTimes::MarshalStrategy.find(message['marshal'] || :ruby)
190
+ marshaler = ModernTimes::MarshalStrategy.find(message['mt:marshal'] || :ruby)
191
191
  return marshaler.unmarshal(message.data)
192
192
  end
193
193
 
@@ -4,23 +4,24 @@ require 'jms'
4
4
  module ModernTimes
5
5
  module JMS
6
6
  class Publisher
7
- attr_reader :producer_options, :persistent, :marshaler, :reply_queue, :response
7
+ attr_reader :producer_options, :persistent, :marshaler, :reply_queue
8
8
 
9
9
  @@dummy_publishing = false
10
10
 
11
11
  # Parameters:
12
12
  # One of the following must be specified
13
- # :queue_name => String: Name of the Queue to publish to
14
- # :topic_name => String: Name of the Topic to publish to
15
- # :virtual_topic_name => String: Name of the Virtual Topic to publish to
13
+ # :queue_name => String: Name of the Queue to publish to
14
+ # :topic_name => String: Name of the Topic to publish to (In general this should not be used as all worker threads will receive all messages)
15
+ # :virtual_topic_name => String: Name of the Virtual Topic to publish to
16
16
  # (ActiveMQ only, see http://activemq.apache.org/virtual-destinations.html
17
- # :destination => Explicit javax::Jms::Destination to use
17
+ # :destination => Explicit javax::Jms::Destination to use
18
18
  # Optional:
19
- # :persistent => true or false (defaults to false)
20
- # :marshal => Symbol: One of :ruby, :string, :json, :bson, :yaml or any registered types (See ModernTimes::MarshalStrategy), defaults to :ruby
21
- # => Module: Module that defines marshal and unmarshal method
22
- # :time_to_live => expiration time in ms for the message
23
- # :response => if true, a temporary reply queue will be setup for handling responses (defaults to false)
19
+ # :time_to_live => expiration time in ms for the message
20
+ # :persistent => true or false (defaults to false)
21
+ # :marshal => Symbol: One of :ruby, :string, :json, :bson, :yaml or any registered types (See ModernTimes::MarshalStrategy), defaults to :ruby
22
+ # :response => if true, a temporary reply queue will be setup for handling responses (defaults to false unless any other mt_response_* options are set)
23
+ # :response_time_to_live => expiration time in ms for the response message(s)
24
+ # :response_persistent => true or false for the response message(s), set to false if you don't want timed out messages ending up in the DLQ (defaults to true unless mt_response_time_to_live is set)
24
25
  def initialize(options)
25
26
  raise "ModernTimes::JMS::Connection has not been initialized" unless ModernTimes::JMS::Connection.inited? || @@dummy_publishing
26
27
  producer_keys = [:queue_name, :topic_name, :virtual_topic_name, :destination]
@@ -33,22 +34,27 @@ module ModernTimes
33
34
  virtual_topic_name = @real_producer_options.delete(:virtual_topic_name)
34
35
  @real_producer_options[:topic_name] = "VirtualTopic.#{virtual_topic_name}" if virtual_topic_name
35
36
 
36
- # If we're in dummy mode, this probably won't be defined
37
- #@persistent = options[:persistent] ? ::JMS::DeliveryMode::PERSISTENT : ::JMS::DeliveryMode::NON_PERSISTENT
38
- @persistent = options[:persistent] ? :persistent : :non_persistent
37
+ @persistent_sym = options[:persistent] ? :persistent : :non_persistent
39
38
  @marshal = options[:marshal] || :ruby
40
39
  @marshaler = ModernTimes::MarshalStrategy.find(@marshal)
41
40
  @time_to_live = options[:time_to_live]
41
+ @response_time_to_live_str = options[:response_time_to_live] && options[:response_time_to_live].to_s
42
+ @response_persistent_str = nil
43
+ @response_persistent_str = (!!options[:response_persistent]).to_s unless options[:response_persistent].nil?
42
44
 
45
+ @is_response = options[:response] || !@response_time_to_live_str.nil? || !@response_persistent_str.nil?
43
46
  @reply_queue = nil
44
- @response = options[:response]
45
- if !@@dummy_publishing && @response
47
+ if !@@dummy_publishing && @is_response
46
48
  ModernTimes::JMS::Connection.session_pool.session do |session|
47
49
  @reply_queue = session.create_destination(:queue_name => :temporary)
48
50
  end
49
51
  end
50
52
  end
51
53
 
54
+ def response?
55
+ @is_response
56
+ end
57
+
52
58
  # Publish the given object to the address.
53
59
  def publish(object, props={})
54
60
  start = Time.now
@@ -56,9 +62,11 @@ module ModernTimes
56
62
  Connection.session_pool.producer(@real_producer_options) do |session, producer|
57
63
  producer.time_to_live = @time_to_live if @time_to_live
58
64
  message = ModernTimes::JMS.create_message(session, @marshaler, object)
59
- message.jms_delivery_mode_sym = @persistent
60
- message.jms_reply_to = @reply_queue if @reply_queue
61
- message['marshal'] = @marshal.to_s
65
+ message.jms_delivery_mode_sym = @persistent_sym
66
+ message.jms_reply_to = @reply_queue if @reply_queue
67
+ message['mt:marshal'] = @marshal.to_s
68
+ message['mt:response:time_to_live'] = @response_time_to_live_str if @response_time_to_live_str
69
+ message['mt:response:persistent'] = @response_persistent_str unless @response_persistent_str.nil?
62
70
  props.each do |key, value|
63
71
  message.send("#{key}=", value)
64
72
  end
@@ -75,7 +83,7 @@ module ModernTimes
75
83
  # Model real queue marshaling/unmarshaling
76
84
  trans_object = @marshaler.unmarshal(@marshaler.marshal(object))
77
85
  @@workers.each do |worker|
78
- if ModernTimes::JMS.same_destination?(@producer_options, worker.class.destination_options)
86
+ if ModernTimes::JMS.same_destination?(@producer_options, worker.destination_options)
79
87
  if worker.kind_of?(RequestWorker)
80
88
  ModernTimes.logger.debug "Dummy request publishing #{trans_object} to #{worker}"
81
89
  m = worker.marshaler
@@ -1,7 +1,7 @@
1
1
  module ModernTimes
2
2
  module JMS
3
3
 
4
- # Base Worker Class for any class that will be processing messages from queues
4
+ # Base Worker Class for any class that will be processing requests from queues and replying
5
5
  module RequestWorker
6
6
  include Worker
7
7
  # Dummy requesting needs access to this
@@ -17,6 +17,11 @@ module ModernTimes
17
17
  # Get the response marshaler, defaulting to the request marshaler
18
18
  @response_options
19
19
  end
20
+
21
+ # By default, exceptions don't get forwarded to a fail queue (they get returned to the caller)
22
+ def default_fail_queue_target
23
+ false
24
+ end
20
25
  end
21
26
 
22
27
  def self.included(base)
@@ -32,40 +37,66 @@ module ModernTimes
32
37
  @marshal_type = (response_options[:marshal] || :ruby).to_s
33
38
  @marshaler = MarshalStrategy.find(@marshal_type)
34
39
  # Time in msec until the message gets discarded, should be more than the timeout on the requestor side
35
- @time_to_live = response_options[:time_to_live] || 10000
40
+ @time_to_live = response_options[:time_to_live]
41
+ @persistent = response_options[:persistent]
36
42
  end
37
43
 
38
44
  def perform(object)
39
45
  response = request(object)
40
- session.producer(:destination => message.reply_to) do |producer|
41
- producer.time_to_live = @time_to_live
42
- reply_message = ModernTimes::JMS.create_message(session, @marshaler, response)
43
- reply_message.jms_correlation_id = message.jms_message_id
44
- reply_message.jms_delivery_mode = ::JMS::DeliveryMode::NON_PERSISTENT
45
- reply_message['worker'] = self.name
46
- reply_message['marshal'] = @marshal_type
47
- producer.send(reply_message)
48
- end
46
+ send_response(@marshal_type, @marshaler, response)
49
47
  rescue Exception => e
50
- ModernTimes.logger.error("Exception: #{e.message}\n\t#{e.backtrace.join("\n\t")}")
48
+ on_exception(e)
49
+ end
50
+
51
+ def request(object)
52
+ raise "#{self}: Need to override request method in #{self.class.name} in order to act on #{object}"
53
+ end
54
+
55
+ #########
56
+ protected
57
+ #########
58
+
59
+ def on_exception(e)
60
+ begin
61
+ stat = send_response(:string, ModernTimes::MarshalStrategy::String, "Exception: #{e.message}") do |reply_message|
62
+ reply_message['mt:exception'] = ModernTimes::RemoteException.new(e).to_hash.to_yaml
63
+ end
64
+ rescue Exception => e
65
+ ModernTimes.logger.error("Exception in exception reply: #{e.message}")
66
+ log_backtrace(e)
67
+ end
68
+
69
+ # Send it on to the fail queue if it was explicitly set
70
+ super
71
+ end
72
+
73
+ # Sending marshaler is redundant but saves a lookup
74
+ def send_response(marshal_type, marshaler, object)
75
+ return false unless message.reply_to
51
76
  begin
52
77
  session.producer(:destination => message.reply_to) do |producer|
53
- producer.time_to_live = @time_to_live
54
- reply_message = ModernTimes::JMS.create_message(session, ModernTimes::MarshalStrategy::String, "Exception: #{e.message}")
78
+ # For time_to_live and jms_deliver_mode, first use the local response_options if they're' set, otherwise
79
+ # use the value from the message attributes if they're' set
80
+ time_to_live = @time_to_live || message['mt:response:time_to_live']
81
+ persistent = @persistent
82
+ persistent = (message['mt:response:persistent'] == 'true') if persistent.nil? && message['mt:response:persistent']
83
+ # If persistent isn't set anywhere, then default to true unless time_to_live has been set
84
+ persistent = !time_to_live if persistent.nil?
85
+ producer.time_to_live = time_to_live.to_i if time_to_live
86
+ reply_message = ModernTimes::JMS.create_message(session, marshaler, object)
55
87
  reply_message.jms_correlation_id = message.jms_message_id
56
- reply_message.jms_delivery_mode = ::JMS::DeliveryMode::NON_PERSISTENT
57
- reply_message['worker'] = self.name
58
- reply_message['exception'] = ModernTimes::RemoteException.new(e).to_hash.to_yaml
88
+ # The reply is persistent if we explicitly set it or if we don't expire
89
+ reply_message.jms_delivery_mode_sym = persistent ? :persistent : :non_persistent
90
+ reply_message['mt:marshal'] = marshal_type.to_s
91
+ reply_message['mt:worker'] = self.name
92
+ yield reply_message if block_given?
59
93
  producer.send(reply_message)
60
94
  end
61
95
  rescue Exception => e
62
- ModernTimes.logger.error("Exception in exception reply: #{e.message}\n\t#{e.backtrace.join("\n\t")}")
96
+ ModernTimes.logger.error {"Error attempting to send response: #{e.message}"}
97
+ log_backtrace(e)
63
98
  end
64
- raise
65
- end
66
-
67
- def request(object)
68
- raise "#{self}: Need to override request method in #{self.class.name} in order to act on #{object}"
99
+ return true
69
100
  end
70
101
  end
71
102
  end
@@ -5,7 +5,7 @@ module ModernTimes
5
5
 
6
6
  # Base Worker Class for any class that will be processing messages from topics or queues
7
7
  # By default, it will consume messages from a queue with the class name minus the Worker postfix.
8
- # For example, the queue call is unneccessary as it will default to a value of 'Foo' anyways:
8
+ # For example, the queue call is unnecessary as it will default to a value of 'Foo' anyways:
9
9
  # class FooWorker < ModernTimes::JMS::Worker
10
10
  # queue 'Foo'
11
11
  # def perform(obj)
@@ -34,7 +34,7 @@ module ModernTimes
34
34
  module Worker
35
35
  include ModernTimes::Base::Worker
36
36
 
37
- attr_reader :session, :error_count, :time_track
37
+ attr_reader :session, :error_count, :time_track, :destination_options
38
38
  attr_accessor :message
39
39
 
40
40
  module ClassMethods
@@ -42,15 +42,6 @@ module ModernTimes
42
42
  Supervisor.new(manager, self, {}, worker_options)
43
43
  end
44
44
 
45
- def destination_options
46
- options = dest_options.dup
47
- # Default the queue name to the Worker name if a destinations hasn't been specified
48
- if options.keys.select {|k| [:virtual_topic_name, :queue_name, :destination].include?(k)}.empty?
49
- options[:queue_name] = default_name
50
- end
51
- return options
52
- end
53
-
54
45
  def virtual_topic(name, opts={})
55
46
  # ActiveMQ only
56
47
  dest_options[:virtual_topic_name] = name.to_s
@@ -60,18 +51,30 @@ module ModernTimes
60
51
  dest_options[:queue_name] = name.to_s
61
52
  end
62
53
 
63
- def dest_options
54
+ def dest_options
64
55
  @dest_options ||= {}
65
56
  end
66
57
 
67
- def failure_queue(name, opts={})
68
- @failure_queue_name = name.to_s
58
+ # Set the fail_queue
59
+ # target =>
60
+ # boolean
61
+ # true - exceptions in the worker will cause the message to be forwarded to the queue of <default-name>Fail
62
+ # For instance, an Exception in FooWorker#perform will forward the message to the queue FooFail
63
+ # false - exceptions will not result in the message being forwarded to a fail queue
64
+ # string - equivalent to true but the string defines the name of the fail queue
65
+ def fail_queue(target, opts={})
66
+ @fail_queue_target = name
69
67
  end
70
68
 
71
- def failure_queue_name
69
+ def fail_queue_target
72
70
  # Don't overwrite if the user set to false, only if it was never set
73
- @failure_queue_name = "#{default_name}Failure" if @failure_queue_name.nil?
74
- @failure_queue_name
71
+ @fail_queue_target
72
+ end
73
+
74
+ # Defines the default value of the fail_queue_target. For extenders of this class, the default will be true
75
+ # but extenders can change this (RequestWorker returns exceptions to the caller so it defaults to false).
76
+ def default_fail_queue_target
77
+ true
75
78
  end
76
79
  end
77
80
 
@@ -82,10 +85,34 @@ module ModernTimes
82
85
 
83
86
  def initialize(opts={})
84
87
  super
88
+ @stopped = false
85
89
  @status = 'initialized'
86
- # Supervisor will ask for counts in a separate thread
87
90
  @time_track = ModernTimes::TimeTrack.new
88
91
  @error_count = 0
92
+ @message_mutex = Mutex.new
93
+
94
+ @destination_options = self.class.dest_options.dup
95
+ # Default the queue name to the Worker name if a destinations hasn't been specified
96
+ if @destination_options.keys.select {|k| [:virtual_topic_name, :queue_name, :destination].include?(k)}.empty?
97
+ @destination_options[:queue_name] = self.name
98
+ end
99
+
100
+ @real_destination_options = @destination_options.dup
101
+ virtual_topic_name = @real_destination_options.delete(:virtual_topic_name)
102
+ @real_destination_options[:queue_name] = "Consumer.#{name}.VirtualTopic.#{virtual_topic_name}" if virtual_topic_name
103
+
104
+ target = opts[:fail_queue]
105
+ target = self.class.fail_queue_target if target.nil?
106
+ target = self.class.default_fail_queue_target if target.nil?
107
+ if target == true
108
+ @fail_queue_name = "#{name}Fail"
109
+ elsif target == false
110
+ @fail_queue_name = nil
111
+ elsif target.kind_of?(String)
112
+ @fail_queue_name = target
113
+ else
114
+ raise "Invalid fail queue: #{target}"
115
+ end
89
116
  end
90
117
 
91
118
  def message_count
@@ -96,25 +123,20 @@ module ModernTimes
96
123
  @status || "Processing message #{@time_track.total_count}"
97
124
  end
98
125
 
99
- def real_destination_options
100
- options = self.class.destination_options
101
- virtual_topic_name = options.delete(:virtual_topic_name)
102
- options[:queue_name] = "Consumer.#{name}.VirtualTopic.#{virtual_topic_name}" if virtual_topic_name
103
- return options
104
- end
105
-
106
126
  # Start the event loop for handling messages off the queue
107
127
  def start
108
128
  @session = Connection.create_consumer_session
109
- @consumer = @session.consumer(real_destination_options)
129
+ @consumer = @session.consumer(@real_destination_options)
110
130
  @session.start
111
131
 
112
132
  ModernTimes.logger.debug "#{self}: Starting receive loop"
113
133
  @status = nil
114
- while msg = @consumer.receive
134
+ while !@stopped && msg = @consumer.receive
115
135
  @time_track.perform do
116
- on_message(msg)
117
- msg.acknowledge
136
+ @message_mutex.synchronize do
137
+ on_message(msg)
138
+ msg.acknowledge
139
+ end
118
140
  end
119
141
  ModernTimes.logger.info {"#{self}::on_message (#{('%.1f' % (@time_track.last_time*1000.0))}ms)"} if ModernTimes::JMS::Connection.log_times?
120
142
  end
@@ -132,46 +154,69 @@ module ModernTimes
132
154
  rescue Exception => e
133
155
  @status = "Exited with exception #{e.message}"
134
156
  ModernTimes.logger.error "#{self}: Exception, thread terminating: #{e.message}\n\t#{e.backtrace.join("\n\t")}"
135
- rescue java.lang.Exception => e
136
- @status = "Exited with java exception #{e.message}"
137
- ModernTimes.logger.error "#{self}: Java exception, thread terminating: #{e.message}\n\t#{e.backtrace.join("\n\t")}"
138
157
  end
139
158
 
140
159
  def stop
141
- @consumer.close if @consumer
142
- @session.close if @session
160
+ @stopped = true
161
+ # Don't clobber the session before a reply
162
+ @message_mutex.synchronize do
163
+ @consumer.close if @consumer
164
+ @session.close if @session
165
+ end
166
+ end
167
+
168
+ def perform(object)
169
+ raise "#{self}: Need to override perform method in #{self.class.name} in order to act on #{object}"
170
+ end
171
+
172
+ def to_s
173
+ "#{@real_destination_options.to_a.join('=>')}:#{index}"
174
+ end
175
+
176
+ #########
177
+ protected
178
+ #########
179
+
180
+ def fail_queue_name
181
+ @fail_queue_name
143
182
  end
144
183
 
145
184
  def on_message(message)
146
185
  @message = message
147
- marshaler = ModernTimes::MarshalStrategy.find(message['marshal'] || :ruby)
186
+ marshaler = ModernTimes::MarshalStrategy.find(message['mt:marshal'] || :ruby)
148
187
  object = marshaler.unmarshal(message.data)
149
188
  ModernTimes.logger.debug {"#{self}: Received Object: #{object}"}
150
189
  perform(object)
151
190
  rescue Exception => e
152
- @error_count += 1
153
191
  on_exception(e)
154
192
  ensure
155
193
  ModernTimes.logger.debug {"#{self}: Finished processing message"}
156
194
  ModernTimes.logger.flush if ModernTimes.logger.respond_to?(:flush)
157
195
  end
158
196
 
159
- def perform(object)
160
- raise "#{self}: Need to override perform method in #{self.class.name} in order to act on #{object}"
197
+ def increment_error_count
198
+ @error_count += 1
161
199
  end
162
200
 
163
201
  def on_exception(e)
164
- ModernTimes.logger.error "#{self}: Messaging Exception: #{e.message}\n\t#{e.backtrace.join("\n\t")}"
165
- if self.class.failure_queue_name
166
- session.producer(:queue_name => self.class.failure_queue_name) do |producer|
202
+ increment_error_count
203
+ ModernTimes.logger.error "#{self}: Messaging Exception: #{e.message}"
204
+ log_backtrace(e)
205
+ if fail_queue_name
206
+ session.producer(:queue_name => fail_queue_name) do |producer|
207
+ # TODO: Can't add attribute to read-only message?
208
+ #message['mt:exception'] = ModernTimes::RemoteException.new(e).to_hash.to_yaml
167
209
  producer.send(message)
168
210
  end
169
211
  end
212
+ rescue Exception => e
213
+ ModernTimes.logger.error "#{self}: Exception in exception reply: #{e.message}"
214
+ log_backtrace(e)
170
215
  end
171
216
 
172
- def to_s
173
- "#{real_destination_options.to_a.join('=>')}:#{index}"
217
+ def log_backtrace(e)
218
+ ModernTimes.logger.error "\t#{e.backtrace.join("\n\t")}"
174
219
  end
175
220
  end
176
221
  end
177
- end
222
+ end
@@ -110,7 +110,6 @@ module ModernTimes
110
110
  end
111
111
  File.open(@persist_file, 'w') do |out|
112
112
  YAML.dump(hash, out )
113
- YAML.dump(hash, out )
114
113
  end
115
114
  end
116
115
 
data/test/jms.yml CHANGED
@@ -3,7 +3,7 @@
3
3
  :log_times: false
4
4
  :require_jars:
5
5
  - <%= Dir.glob("#{ENV['ACTIVEMQ_HOME']}/activemq-all-*.jar")[0] %>
6
- #- <%= Dir.glob("#{ENV['ACTIVEMQ_HOME']}/lib/optional/slf4j-log4j*.jar")[0] %>
7
- #- <%= Dir.glob("#{ENV['ACTIVEMQ_HOME']}/lib/optional/log4j-*.jar")[0] %>
6
+ - <%= Dir.glob("#{ENV['ACTIVEMQ_HOME']}/lib/optional/slf4j-log4j*.jar")[0] %>
7
+ - <%= Dir.glob("#{ENV['ACTIVEMQ_HOME']}/lib/optional/log4j-*.jar")[0] %>
8
8
  #:username: myuser
9
9
  #:password: mypassword
@@ -0,0 +1,149 @@
1
+ require 'modern_times'
2
+ require 'shoulda'
3
+ require 'test/unit'
4
+ require 'fileutils'
5
+ require 'erb'
6
+
7
+ # NOTE: This test requires a running ActiveMQ server
8
+
9
+ class ExceptionWorker
10
+ include ModernTimes::JMS::Worker
11
+ def perform(obj)
12
+ puts "#{name} received #{obj} but raising exception"
13
+ raise 'foobar'
14
+ end
15
+
16
+ def log_backtrace(e)
17
+ end
18
+ end
19
+
20
+ class ExceptionRequestWorker
21
+ include ModernTimes::JMS::RequestWorker
22
+
23
+ def request(obj)
24
+ puts "#{name} received #{obj} but raising exception"
25
+ raise 'foobar'
26
+ end
27
+
28
+ def log_backtrace(e)
29
+ end
30
+ end
31
+
32
+ # This will read from the queue that ExceptionWorker fails to
33
+ class ExceptionFailWorker
34
+ include ModernTimes::JMS::Worker
35
+
36
+ @@my_hash = {}
37
+
38
+ def self.my_obj(name)
39
+ @@my_hash[name]
40
+ end
41
+
42
+ def perform(obj)
43
+ puts "#{name} received #{obj}"
44
+ @@my_hash[name] = obj
45
+ end
46
+ end
47
+
48
+ class JMSFailTest < Test::Unit::TestCase
49
+
50
+ def assert_fail_queue(queue_name, fail_queue_name, value, is_fail_queue_expected)
51
+ # Publish to Exception that will throw exception which will put on ExceptionFail queue
52
+ publisher = ModernTimes::JMS::Publisher.new(:queue_name => queue_name, :marshal => :string)
53
+ puts "Publishing #{value} to #{queue_name}"
54
+ publisher.publish(value)
55
+ sleep 1
56
+ expected_value = (is_fail_queue_expected ? value : nil)
57
+ assert_equal expected_value, ExceptionFailWorker.my_obj(fail_queue_name)
58
+ end
59
+
60
+ context 'jms' do
61
+ setup do
62
+ config = YAML.load(ERB.new(File.read(File.join(File.dirname(__FILE__), 'jms.yml'))).result(binding))
63
+ ModernTimes::JMS::Connection.init(config)
64
+ end
65
+
66
+ teardown do
67
+ end
68
+
69
+ context "worker with exception" do
70
+ setup do
71
+ @manager = ModernTimes::Manager.new
72
+
73
+ # Should receive message on the fail worker when using with default names
74
+ @manager.add(ExceptionWorker, 1)
75
+ @manager.add(ExceptionFailWorker, 1)
76
+
77
+ # Should receive message on the fail worker when using specified names
78
+ name = 'ExceptionNameSpecified'
79
+ @manager.add(ExceptionWorker, 1, :name => name)
80
+ @manager.add(ExceptionFailWorker, 1, :name => "#{name}Fail")
81
+
82
+ # Should receive message on the fail worker when using specified names and fail_queue set true
83
+ name = 'ExceptionFailQueueTrue'
84
+ @manager.add(ExceptionWorker, 1, :name => name, :fail_queue => true)
85
+ @manager.add(ExceptionFailWorker, 1, :name => "#{name}Fail")
86
+
87
+ # Should NOT receive message on the fail worker when using specified names and fail_queue set false
88
+ name = 'ExceptionFailQueueFalse'
89
+ @manager.add(ExceptionWorker, 1, :name => name, :fail_queue => false)
90
+ @manager.add(ExceptionFailWorker, 1, :name => "#{name}Fail")
91
+
92
+ # Should NOT receive message on the fail worker when using specified names and fail_queue set false
93
+ name = 'ExceptionFailQueueSpecified'
94
+ fail_queue = 'MyFailQueue'
95
+ @manager.add(ExceptionWorker, 1, :name => name, :fail_queue => fail_queue)
96
+ @manager.add(ExceptionFailWorker, 1, :name => fail_queue)
97
+
98
+ # Should NOT receive message on the fail worker
99
+ name = 'ExceptionRequest'
100
+ @manager.add(ExceptionRequestWorker, 1)
101
+ @manager.add(ExceptionFailWorker, 1, :name => "#{name}Fail")
102
+
103
+ # Should NOT receive message on the fail worker when using specified names
104
+ name = 'ExceptionRequestNameSpecified'
105
+ @manager.add(ExceptionRequestWorker, 1, :name => name)
106
+ @manager.add(ExceptionFailWorker, 1, :name => "#{name}Fail")
107
+
108
+ # Should receive message on the fail worker when using specified names and fail_queue set true
109
+ name = 'ExceptionRequestFailQueueTrue'
110
+ @manager.add(ExceptionRequestWorker, 1, :name => name, :fail_queue => true)
111
+ @manager.add(ExceptionFailWorker, 1, :name => "#{name}Fail")
112
+
113
+ # Should NOT receive message on the fail worker when using specified names and fail_queue set false
114
+ name = 'ExceptionRequestFailQueueFalse'
115
+ @manager.add(ExceptionRequestWorker, 1, :name => name, :fail_queue => false)
116
+ @manager.add(ExceptionFailWorker, 1, :name => "#{name}Fail")
117
+
118
+ # Should NOT receive message on the fail worker when using specified names and fail_queue set false
119
+ name = 'ExceptionRequestFailQueueSpecified'
120
+ fail_queue = 'MyRequestFailQueue'
121
+ @manager.add(ExceptionRequestWorker, 1, :name => name, :fail_queue => fail_queue)
122
+ @manager.add(ExceptionFailWorker, 1, :name => fail_queue)
123
+
124
+ sleep 1
125
+ end
126
+
127
+ teardown do
128
+ if @manager
129
+ @manager.stop
130
+ @manager.join
131
+ end
132
+ end
133
+
134
+ should "write fail messages to a fail queue" do
135
+ assert_fail_queue('Exception', 'ExceptionFail', 'value0', true)
136
+ assert_fail_queue('ExceptionNameSpecified', 'ExceptionNameSpecifiedFail', 'value1', true)
137
+ assert_fail_queue('ExceptionFailQueueTrue', 'ExceptionFailQueueTrueFail', 'value2', true)
138
+ assert_fail_queue('ExceptionFailQueueFalse', 'ExceptionFailQueueFalseFail', 'value3', false)
139
+ assert_fail_queue('ExceptionFailQueueSpecified', 'MyFailQueue', 'value4', true)
140
+
141
+ assert_fail_queue('ExceptionRequest', 'ExceptionRequestFail', 'value5', false)
142
+ assert_fail_queue('ExceptionRequestNameSpecified', 'ExceptionRequestNameSpecifiedFail', 'value6', false)
143
+ assert_fail_queue('ExceptionRequestFailQueueTrue', 'ExceptionRequestFailQueueTrueFail', 'value7', true)
144
+ assert_fail_queue('ExceptionRequestFailQueueFalse', 'ExceptionRequestFailQueueFalseFail', 'value8', false)
145
+ assert_fail_queue('ExceptionRequestFailQueueSpecified', 'MyRequestFailQueue', 'value9', true)
146
+ end
147
+ end
148
+ end
149
+ end
@@ -29,11 +29,14 @@ class BaseRequestWorker
29
29
  raise Exception,'my exception' if self.class.do_exception
30
30
  sleep self.class.sleep_time if self.class.sleep_time
31
31
  end
32
+
33
+ def log_backtrace(e)
34
+ end
32
35
  end
33
36
 
34
37
  class CharCountWorker < BaseRequestWorker
35
38
  virtual_topic 'test_string'
36
- response :marshal => :bson, :time_to_live => 10000
39
+ response :marshal => :bson
37
40
 
38
41
  def request(obj)
39
42
  super
@@ -45,7 +48,7 @@ end
45
48
 
46
49
  class LengthWorker < BaseRequestWorker
47
50
  virtual_topic 'test_string'
48
- response :marshal => :ruby, :time_to_live => 10000
51
+ response :marshal => :ruby
49
52
 
50
53
  def request(obj)
51
54
  super
@@ -55,7 +58,7 @@ end
55
58
 
56
59
  class ReverseWorker < BaseRequestWorker
57
60
  virtual_topic 'test_string'
58
- response :marshal => :string, :time_to_live => 10000
61
+ response :marshal => :string
59
62
 
60
63
  def request(obj)
61
64
  super
@@ -65,7 +68,7 @@ end
65
68
 
66
69
  class TripleWorker < BaseRequestWorker
67
70
  virtual_topic 'test_string'
68
- response :marshal => :string, :time_to_live => 10000
71
+ response :marshal => :string
69
72
 
70
73
  def request(obj)
71
74
  super
@@ -175,7 +178,7 @@ class JMSRequestorBlockTest < Test::Unit::TestCase
175
178
 
176
179
  should "handle replies" do
177
180
 
178
- publisher = ModernTimes::JMS::Publisher.new(:virtual_topic_name => 'test_string', :response => true, :marshal => :string)
181
+ publisher = ModernTimes::JMS::Publisher.new(:virtual_topic_name => 'test_string', :response_time_to_live => 10000, :marshal => :string)
179
182
  cc_val = {'f' => 1, 'o' => 4, 'b' => 1}
180
183
 
181
184
  hash = make_call(publisher, 'fooboo', 2)
@@ -76,7 +76,7 @@ end
76
76
 
77
77
  class DefaultWorker
78
78
  include ModernTimes::JMS::RequestWorker
79
- response :marshal => :yaml, :time_to_live => 10000
79
+ response :marshal => :yaml
80
80
 
81
81
  def request(obj)
82
82
  options[:tester].request(obj)
@@ -85,7 +85,7 @@ end
85
85
 
86
86
  class SleepWorker
87
87
  include ModernTimes::JMS::RequestWorker
88
- response :marshal => :string, :time_to_live => 10000
88
+ response :marshal => :string
89
89
 
90
90
  def request(i)
91
91
  sleep i.to_i
@@ -134,7 +134,7 @@ class JMSRequestorTest < Test::Unit::TestCase
134
134
 
135
135
  sleep 1
136
136
 
137
- publisher = ModernTimes::JMS::Publisher.new(:queue_name => 'Default', :marshal => marshal, :response => true)
137
+ publisher = ModernTimes::JMS::Publisher.new(:queue_name => 'Default', :marshal => marshal, :response_time_to_live => 10000)
138
138
  threads = []
139
139
  start = Time.now
140
140
  (0..9).each do |i|
@@ -161,7 +161,7 @@ class JMSRequestorTest < Test::Unit::TestCase
161
161
  @manager = ModernTimes::Manager.new(:domain => @domain)
162
162
  @manager.add(SleepWorker, 10)
163
163
  sleep 1
164
- @publisher = ModernTimes::JMS::Publisher.new(:queue_name => 'Sleep', :marshal => :string, :response => true)
164
+ @publisher = ModernTimes::JMS::Publisher.new(:queue_name => 'Sleep', :marshal => :string, :response_time_to_live => 10000)
165
165
  end
166
166
 
167
167
  teardown do
data/test/jms_test.rb CHANGED
@@ -13,8 +13,8 @@ module WorkerHelper
13
13
  super
14
14
  @tester = opts[:tester]
15
15
  @@mutex.synchronize do
16
- @@workers[self.class.name] ||= []
17
- @@workers[self.class.name] << self
16
+ @@workers[self.name] ||= []
17
+ @@workers[self.name] << self
18
18
  end
19
19
  @hash = Hash.new(0)
20
20
  end
@@ -23,8 +23,10 @@ module WorkerHelper
23
23
  add_message(@tester.translate(obj))
24
24
  end
25
25
 
26
- def self.workers(worker_klass)
27
- @@workers[worker_klass.name]
26
+ def self.workers(names)
27
+ workers = []
28
+ names.each {|name| workers += @@workers[name]}
29
+ workers
28
30
  end
29
31
 
30
32
  def self.reset_workers
@@ -35,7 +37,7 @@ module WorkerHelper
35
37
  @hash[i] += 1
36
38
  end
37
39
 
38
- def message_count
40
+ def call_count
39
41
  puts "hash=#{@hash.inspect}"
40
42
  @hash.values.reduce(:+)
41
43
  end
@@ -144,17 +146,15 @@ class JMSTest < Test::Unit::TestCase
144
146
  end
145
147
  end
146
148
 
147
- def assert_worker(domain, worker_klasses, mbean_names, worker_count, range, min, max, instance_count)
148
- puts "Checking #{worker_klasses.inspect}"
149
- worker_klasses = [worker_klasses] unless worker_klasses.kind_of?(Array)
150
- mbean_names = [mbean_names] unless mbean_names.kind_of?(Array)
151
- workers = []
152
- worker_klasses.each {|klass| workers.concat(WorkerHelper.workers(klass))}
149
+ def assert_worker(domain, names, worker_count, range, min, max, instance_count)
150
+ puts "Checking #{names.inspect}"
151
+ names = [names] unless names.kind_of?(Array)
152
+ workers = WorkerHelper.workers(names)
153
153
 
154
154
  assert_equal worker_count, workers.size
155
155
  all_messages = []
156
156
  workers.each do |worker|
157
- msg_count = worker.message_count
157
+ msg_count = worker.call_count
158
158
  assert msg_count
159
159
  assert msg_count >= min, "#{msg_count} is not between #{min} and #{max}"
160
160
  assert msg_count <= max, "#{msg_count} is not between #{min} and #{max}"
@@ -167,8 +167,8 @@ class JMSTest < Test::Unit::TestCase
167
167
 
168
168
  if domain
169
169
  total_count = 0
170
- mbean_names.each do |mbean_name|
171
- bean = @@client[ModernTimes.supervisor_mbean_object_name(domain, mbean_name)]
170
+ names.each do |name|
171
+ bean = @@client[ModernTimes.supervisor_mbean_object_name(domain, name)]
172
172
  bean.message_counts.each do |msg_count|
173
173
  total_count += msg_count
174
174
  assert msg_count >= min, "#{msg_count} is not between #{min} and #{max}"
@@ -224,19 +224,21 @@ class JMSTest < Test::Unit::TestCase
224
224
  sleep 1
225
225
 
226
226
  publish(marshal, tester, 100..199, :queue_name => 'Default')
227
- publish(marshal, tester, 200..299, :queue_name => 'Dummy_Default')
228
- publish(marshal, tester, 300..499, :queue_name => 'MyQueueName')
229
- publish(marshal, tester, 500..599, :virtual_topic_name => 'MyTopicName')
227
+ publish(marshal, tester, 200..299, :queue_name => 'DefaultClone')
228
+ publish(marshal, tester, 300..399, :queue_name => 'Dummy_Default')
229
+ publish(marshal, tester, 400..599, :queue_name => 'MyQueueName')
230
+ publish(marshal, tester, 600..699, :virtual_topic_name => 'MyTopicName')
230
231
 
231
232
  # Let the workers do their thing
232
233
  sleep 5
233
234
 
234
235
  # DefaultWorker should have 5 instances running with each worker handling between 10-30 messages in the range 100.199
235
- assert_worker(@domain, DefaultWorker, ['Default', 'DefaultClone'], 5, 100..199, 10, 30, 1)
236
- assert_worker(@domain, Dummy::DefaultWorker, 'Dummy_Default', 4, 200..299, 15, 35, 1)
237
- assert_worker(@domain, [SpecifiedQueueWorker,SpecifiedQueue2Worker], ['SpecifiedQueue', 'SpecifiedQueueClone', 'SpecifiedQueue2'], 7, 300..499, 20, 40, 1)
238
- assert_worker(@domain, SpecifiedTopicWorker, ['SpecifiedTopic', 'SpecifiedTopicClone'], 5, 500..599, 30, 60, 2)
239
- assert_worker(@domain, SpecifiedTopic2Worker, 'SpecifiedTopic2', 2, 500..599, 35, 65, 1)
236
+ assert_worker(@domain, 'Default', 3, 100..199, 30, 36, 1)
237
+ assert_worker(@domain, 'DefaultClone', 2, 200..299, 45, 55, 1)
238
+ assert_worker(@domain, 'Dummy_Default', 4, 300..399, 20, 30, 1)
239
+ assert_worker(@domain, ['SpecifiedQueue', 'SpecifiedQueueClone', 'SpecifiedQueue2'], 7, 400..599, 20, 40, 1)
240
+ assert_worker(@domain, ['SpecifiedTopic', 'SpecifiedTopicClone'], 5, 600..699, 30, 60, 2)
241
+ assert_worker(@domain, 'SpecifiedTopic2', 2, 600..699, 35, 65, 1)
240
242
  end
241
243
  end
242
244
  end
@@ -246,10 +248,13 @@ class JMSTest < Test::Unit::TestCase
246
248
  WorkerHelper.reset_workers
247
249
  workers = [
248
250
  DefaultWorker.new(:tester => RubyTest),
251
+ DefaultWorker.new(:tester => RubyTest, :name => 'DefaultClone'),
249
252
  Dummy::DefaultWorker.new(:tester => RubyTest),
250
253
  SpecifiedQueueWorker.new(:tester => RubyTest),
254
+ SpecifiedQueueWorker.new(:tester => RubyTest, :name => 'SpecifiedQueueClone'),
251
255
  SpecifiedQueue2Worker.new(:tester => RubyTest),
252
256
  SpecifiedTopicWorker.new(:tester => RubyTest),
257
+ SpecifiedTopicWorker.new(:tester => RubyTest, :name => 'SpecifiedTopicClone'),
253
258
  SpecifiedTopic2Worker.new(:tester => RubyTest),
254
259
  ]
255
260
  ModernTimes::JMS::Publisher.setup_dummy_publishing(workers)
@@ -261,17 +266,21 @@ class JMSTest < Test::Unit::TestCase
261
266
 
262
267
  should "directly call applicable workers" do
263
268
  publish(:ruby, RubyTest, 100..199, :queue_name => 'Default')
264
- publish(:ruby, RubyTest, 200..299, :queue_name => 'Dummy_Default')
265
- publish(:ruby, RubyTest, 300..499, :queue_name => 'MyQueueName')
266
- publish(:ruby, RubyTest, 500..599, :virtual_topic_name => 'MyTopicName')
267
-
268
- # DefaultWorker should have 5 instances running with each worker handling between 10-30 messages in the range 100.199
269
- assert_worker(nil, DefaultWorker, nil, 1, 100..199, 100, 100, 1)
270
- assert_worker(nil, Dummy::DefaultWorker, nil, 1, 200..299, 100, 100, 1)
271
- assert_worker(nil, SpecifiedQueueWorker, nil, 1, 300..499, 200, 200, 1)
272
- assert_worker(nil, SpecifiedQueue2Worker, nil, 1, 300..499, 200, 200, 1)
273
- assert_worker(nil, SpecifiedTopicWorker, nil, 1, 500..599, 100, 100, 1)
274
- assert_worker(nil, SpecifiedTopic2Worker, nil, 1, 500..599, 100, 100, 1)
269
+ publish(:ruby, RubyTest, 200..299, :queue_name => 'DefaultClone')
270
+ publish(:ruby, RubyTest, 300..399, :queue_name => 'Dummy_Default')
271
+ publish(:ruby, RubyTest, 400..599, :queue_name => 'MyQueueName')
272
+ publish(:ruby, RubyTest, 600..699, :virtual_topic_name => 'MyTopicName')
273
+
274
+ # The single instance of each class will be called so everyone will have all messages.
275
+ assert_worker(nil, 'Default', 1, 100..199, 100, 100, 1)
276
+ assert_worker(nil, 'DefaultClone', 1, 200..299, 100, 100, 1)
277
+ assert_worker(nil, 'Dummy_Default', 1, 300..399, 100, 100, 1)
278
+ assert_worker(nil, 'SpecifiedQueue', 1, 400..599, 200, 200, 1)
279
+ assert_worker(nil, 'SpecifiedQueueClone', 1, 400..599, 200, 200, 1)
280
+ assert_worker(nil, 'SpecifiedQueue2', 1, 400..599, 200, 200, 1)
281
+ assert_worker(nil, 'SpecifiedTopic', 1, 600..699, 100, 100, 1)
282
+ assert_worker(nil, 'SpecifiedTopicClone', 1, 600..699, 100, 100, 1)
283
+ assert_worker(nil, 'SpecifiedTopic2', 1, 600..699, 100, 100, 1)
275
284
  end
276
285
  end
277
286
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: modern_times
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.3.1
5
+ version: 0.3.2
6
6
  platform: ruby
7
7
  authors:
8
8
  - Brad Pardee
@@ -11,7 +11,7 @@ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
13
 
14
- date: 2011-05-18 00:00:00 -04:00
14
+ date: 2011-05-31 00:00:00 -04:00
15
15
  default_executable:
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
@@ -48,9 +48,11 @@ extra_rdoc_files:
48
48
  - LICENSE.txt
49
49
  - README.rdoc
50
50
  files:
51
+ - History.md
51
52
  - LICENSE.txt
52
53
  - README.rdoc
53
54
  - Rakefile
55
+ - TODO.md
54
56
  - VERSION
55
57
  - examples/README
56
58
  - examples/advanced_requestor/README
@@ -105,7 +107,7 @@ files:
105
107
  - lib/modern_times/time_track.rb
106
108
  - test/base_test.rb
107
109
  - test/jms.yml
108
- - test/jms_failure_test.rb
110
+ - test/jms_fail_test.rb
109
111
  - test/jms_requestor_block_test.rb
110
112
  - test/jms_requestor_test.rb
111
113
  - test/jms_test.rb
@@ -157,7 +159,7 @@ test_files:
157
159
  - examples/simple/manager.rb
158
160
  - examples/simple/publish.rb
159
161
  - test/base_test.rb
160
- - test/jms_failure_test.rb
162
+ - test/jms_fail_test.rb
161
163
  - test/jms_requestor_block_test.rb
162
164
  - test/jms_requestor_test.rb
163
165
  - test/jms_test.rb
@@ -1,128 +0,0 @@
1
- require 'modern_times'
2
- require 'shoulda'
3
- require 'test/unit'
4
- require 'fileutils'
5
- require 'erb'
6
-
7
- # NOTE: This test requires a running ActiveMQ server
8
-
9
- class ExceptionWorker
10
- include ModernTimes::JMS::Worker
11
-
12
- def perform(obj)
13
- puts "ExceptinoWorker received #{obj} but raising exception"
14
- raise 'foobar'
15
- end
16
- end
17
-
18
- # This will read from the queue that ExceptionWorker fails to
19
- class ExceptionFailureWorker
20
- include ModernTimes::JMS::Worker
21
-
22
- def self.my_obj
23
- @@my_obj
24
- end
25
-
26
- def perform(obj)
27
- puts "ExceptinoFailureWorker received #{obj}"
28
- @@my_obj = obj
29
- end
30
- end
31
-
32
- class JMSFailureTest < Test::Unit::TestCase
33
-
34
- context 'jms' do
35
- setup do
36
- config = YAML.load(ERB.new(File.read(File.join(File.dirname(__FILE__), 'jms.yml'))).result(binding))
37
- ModernTimes::JMS::Connection.init(config)
38
- end
39
-
40
- teardown do
41
- end
42
-
43
- context "worker with exception" do
44
- setup do
45
- @manager = ModernTimes::Manager.new
46
-
47
- @manager.add(ExceptionWorker, 1)
48
- @manager.add(ExceptionFailureWorker, 1)
49
-
50
- sleep 1
51
- end
52
-
53
- teardown do
54
- if @manager
55
- @manager.stop
56
- @manager.join
57
- end
58
- end
59
-
60
- should "write failure messages to a queue of <name>Failure" do
61
-
62
- # Publish to Exception that will throw exception which will put on ExceptionFailure queue
63
- publisher = ModernTimes::JMS::Publisher.new(:queue_name => 'Exception', :marshal => :string)
64
- publisher.publish('zulu')
65
- sleep 1
66
- assert_equal 'zulu', ExceptionFailureWorker.my_obj
67
- end
68
- end
69
-
70
- # context "dummy publishing" do
71
- # setup do
72
- # workers = [
73
- # CharCountWorker.new,
74
- # CharCountWorker.new(:name => 'CharCount2'),
75
- # LengthWorker.new,
76
- # LengthWorker.new(:name => 'Length2'),
77
- # ReverseWorker.new,
78
- # TripleWorker.new,
79
- # HolderWorker.new,
80
- # ]
81
- # ModernTimes::JMS::Publisher.setup_dummy_publishing(workers)
82
- # end
83
- #
84
- # teardown do
85
- # ModernTimes::JMS::Publisher.clear_dummy_publishing
86
- # end
87
- #
88
- # should "handle replies" do
89
- #
90
- # publisher = ModernTimes::JMS::Publisher.new(:virtual_topic_name => 'test_string', :response => true, :marshal => :string)
91
- # cc_val = {'f' => 1, 'o' => 4, 'b' => 1}
92
- #
93
- # hash = make_call(publisher, 'fooboo', 2)
94
- # assert_response(hash['CharCount'], :message, cc_val)
95
- # assert_response(hash['CharCount2'], :message, cc_val)
96
- # assert_response(hash['Length'], :message, 6)
97
- # assert_response(hash['Length2'], :message, 6)
98
- # assert_response(hash['Reverse'], :message, 'ooboof')
99
- # assert_response(hash['Triple'], :message, 'fooboofooboofooboo')
100
- #
101
- # # Timeouts don't occur when dummy publishing
102
- # CharCountWorker.sleep_time = 3
103
- # ReverseWorker.sleep_time = 3
104
- # hash = make_call(publisher, 'fooboo', 2)
105
- # assert_response(hash['CharCount'], :message, cc_val)
106
- # assert_response(hash['CharCount2'], :message, cc_val)
107
- # assert_response(hash['Length'], :message, 6)
108
- # assert_response(hash['Length2'], :message, 6)
109
- # assert_response(hash['Reverse'], :message, 'ooboof')
110
- # assert_response(hash['Triple'], :message, 'fooboofooboofooboo')
111
- # CharCountWorker.sleep_time = nil
112
- # ReverseWorker.sleep_time = nil
113
- #
114
- # CharCountWorker.do_exception = true
115
- # TripleWorker.do_exception = true
116
- # hash = make_call(publisher, 'fooboo', 2)
117
- # assert_exception(hash['CharCount'], :explicit_exception)
118
- # assert_exception(hash['CharCount2'], :default_exception)
119
- # assert_response(hash['Length'], :message, 6)
120
- # assert_response(hash['Length2'], :message, 6)
121
- # assert_response(hash['Reverse'], :message, 'ooboof')
122
- # assert_exception(hash['Triple'], :default_exception)
123
- # CharCountWorker.do_exception = false
124
- # TripleWorker.do_exception = false
125
- # end
126
- # end
127
- end
128
- end