modern_times 0.3.1 → 0.3.2
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.
- data/History.md +9 -0
- data/README.rdoc +3 -8
- data/TODO.md +10 -0
- data/VERSION +1 -1
- data/examples/simple/.gitignore +1 -1
- data/examples/simple/README +3 -2
- data/examples/simple/bar_worker.rb +0 -1
- data/examples/simple/baz_worker.rb +0 -1
- data/examples/simple/manager.rb +1 -1
- data/lib/modern_times/base/supervisor.rb +1 -6
- data/lib/modern_times/base/worker.rb +4 -0
- data/lib/modern_times/jms/publish_handle.rb +4 -4
- data/lib/modern_times/jms/publisher.rb +27 -19
- data/lib/modern_times/jms/request_worker.rb +54 -23
- data/lib/modern_times/jms/worker.rb +89 -44
- data/lib/modern_times/manager.rb +0 -1
- data/test/jms.yml +2 -2
- data/test/jms_fail_test.rb +149 -0
- data/test/jms_requestor_block_test.rb +8 -5
- data/test/jms_requestor_test.rb +4 -4
- data/test/jms_test.rb +42 -33
- metadata +6 -4
- data/test/jms_failure_test.rb +0 -128
data/History.md
ADDED
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:
|
38
|
+
:password: mypassword
|
44
39
|
|
45
40
|
production:
|
46
41
|
<<: *defaults
|
47
|
-
:broker_url: failover://(tcp://msg1:61616,tcp://msg2:61616)?randomize=false&
|
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:
|
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
|
+
0.3.2
|
data/examples/simple/.gitignore
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
data
|
2
|
-
|
2
|
+
modern_times.yml
|
data/examples/simple/README
CHANGED
@@ -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.
|
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
|
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
|
data/examples/simple/manager.rb
CHANGED
@@ -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.
|
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.
|
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)
|
@@ -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
|
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
|
14
|
-
# :topic_name
|
15
|
-
# :virtual_topic_name
|
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
|
17
|
+
# :destination => Explicit javax::Jms::Destination to use
|
18
18
|
# Optional:
|
19
|
-
# :
|
20
|
-
# :
|
21
|
-
#
|
22
|
-
# :
|
23
|
-
# :
|
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
|
-
|
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
|
-
|
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
|
60
|
-
message.jms_reply_to
|
61
|
-
message['marshal']
|
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.
|
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
|
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]
|
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
|
-
|
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
|
-
|
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
|
-
|
54
|
-
|
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
|
-
|
57
|
-
reply_message
|
58
|
-
reply_message['
|
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
|
96
|
+
ModernTimes.logger.error {"Error attempting to send response: #{e.message}"}
|
97
|
+
log_backtrace(e)
|
63
98
|
end
|
64
|
-
|
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
|
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
|
-
|
54
|
+
def dest_options
|
64
55
|
@dest_options ||= {}
|
65
56
|
end
|
66
57
|
|
67
|
-
|
68
|
-
|
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
|
69
|
+
def fail_queue_target
|
72
70
|
# Don't overwrite if the user set to false, only if it was never set
|
73
|
-
@
|
74
|
-
|
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
|
-
|
117
|
-
|
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
|
-
@
|
142
|
-
|
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
|
160
|
-
|
197
|
+
def increment_error_count
|
198
|
+
@error_count += 1
|
161
199
|
end
|
162
200
|
|
163
201
|
def on_exception(e)
|
164
|
-
|
165
|
-
|
166
|
-
|
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
|
173
|
-
"#{
|
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
|
data/lib/modern_times/manager.rb
CHANGED
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
|
-
|
7
|
-
|
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
|
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
|
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
|
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
|
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', :
|
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)
|
data/test/jms_requestor_test.rb
CHANGED
@@ -76,7 +76,7 @@ end
|
|
76
76
|
|
77
77
|
class DefaultWorker
|
78
78
|
include ModernTimes::JMS::RequestWorker
|
79
|
-
response :marshal => :yaml
|
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
|
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, :
|
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, :
|
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.
|
17
|
-
@@workers[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(
|
27
|
-
|
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
|
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,
|
148
|
-
puts "Checking #{
|
149
|
-
|
150
|
-
|
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.
|
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
|
-
|
171
|
-
bean = @@client[ModernTimes.supervisor_mbean_object_name(domain,
|
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 => '
|
228
|
-
publish(marshal, tester, 300..
|
229
|
-
publish(marshal, tester,
|
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,
|
236
|
-
assert_worker(@domain,
|
237
|
-
assert_worker(@domain,
|
238
|
-
assert_worker(@domain,
|
239
|
-
assert_worker(@domain,
|
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 => '
|
265
|
-
publish(:ruby, RubyTest, 300..
|
266
|
-
publish(:ruby, RubyTest,
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
assert_worker(nil,
|
271
|
-
assert_worker(nil,
|
272
|
-
assert_worker(nil,
|
273
|
-
assert_worker(nil,
|
274
|
-
assert_worker(nil,
|
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.
|
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-
|
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/
|
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/
|
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
|
data/test/jms_failure_test.rb
DELETED
@@ -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
|