qwirk 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +9 -14
- data/lib/qwirk.rb +26 -17
- data/lib/qwirk/adapter.rb +3 -45
- data/lib/qwirk/adapter/base.rb +2 -0
- data/lib/qwirk/adapter/base/expanding_worker_config.rb +133 -0
- data/lib/qwirk/adapter/base/worker_config.rb +104 -0
- data/lib/qwirk/adapter/in_memory.rb +13 -0
- data/lib/qwirk/{queue_adapter/in_mem → adapter/in_memory}/factory.rb +2 -2
- data/lib/qwirk/{queue_adapter/in_mem → adapter/in_memory}/publisher.rb +4 -4
- data/lib/qwirk/{queue_adapter/in_mem → adapter/in_memory}/queue.rb +3 -2
- data/lib/qwirk/{queue_adapter/in_mem → adapter/in_memory}/reply_queue.rb +3 -2
- data/lib/qwirk/{queue_adapter/in_mem → adapter/in_memory}/topic.rb +2 -2
- data/lib/qwirk/{queue_adapter/in_mem → adapter/in_memory}/worker.rb +6 -8
- data/lib/qwirk/adapter/in_memory/worker_config.rb +50 -0
- data/lib/qwirk/adapter/inline.rb +9 -0
- data/lib/qwirk/adapter/inline/publisher.rb +86 -0
- data/lib/qwirk/adapter/inline/worker.rb +55 -0
- data/lib/qwirk/adapter/inline/worker_config.rb +30 -0
- data/lib/qwirk/adapter_factory.rb +48 -0
- data/lib/qwirk/base_worker.rb +18 -28
- data/lib/qwirk/batch/file_worker.rb +4 -4
- data/lib/qwirk/manager.rb +11 -8
- data/lib/qwirk/marshal_strategy/none.rb +1 -1
- data/lib/qwirk/publish_handle.rb +22 -11
- data/lib/qwirk/publisher.rb +9 -9
- data/lib/qwirk/{request_worker.rb → reply_worker.rb} +3 -3
- data/lib/qwirk/worker.rb +27 -29
- data/test/jms_fail_test.rb +11 -11
- data/test/jms_requestor_block_test.rb +12 -12
- data/test/jms_requestor_test.rb +8 -8
- data/test/jms_test.rb +10 -10
- metadata +104 -185
- data/examples/README +0 -1
- data/examples/activemq.xml +0 -84
- data/examples/advanced_requestor/README.md +0 -15
- data/examples/advanced_requestor/base_request_worker.rb +0 -18
- data/examples/advanced_requestor/char_count_worker.rb +0 -16
- data/examples/advanced_requestor/config.ru +0 -24
- data/examples/advanced_requestor/exception_raiser_worker.rb +0 -17
- data/examples/advanced_requestor/length_worker.rb +0 -14
- data/examples/advanced_requestor/print_worker.rb +0 -14
- data/examples/advanced_requestor/publisher.rb +0 -49
- data/examples/advanced_requestor/qwirk.yml +0 -16
- data/examples/advanced_requestor/reverse_worker.rb +0 -14
- data/examples/advanced_requestor/triple_worker.rb +0 -14
- data/examples/batch/my_batch_worker.rb +0 -30
- data/examples/batch/my_line_worker.rb +0 -8
- data/examples/qwirk.yml +0 -20
- data/examples/requestor/README.md +0 -13
- data/examples/requestor/config.ru +0 -13
- data/examples/requestor/qwirk_persist.yml +0 -5
- data/examples/requestor/requestor.rb +0 -68
- data/examples/requestor/reverse_echo_worker.rb +0 -15
- data/examples/setup.rb +0 -13
- data/examples/shared/README.md +0 -24
- data/examples/shared/config.ru +0 -13
- data/examples/shared/publisher.rb +0 -49
- data/examples/shared/qwirk_persist.yml +0 -5
- data/examples/shared/shared_worker.rb +0 -16
- data/examples/simple/README +0 -53
- data/examples/simple/bar_worker.rb +0 -10
- data/examples/simple/baz_worker.rb +0 -10
- data/examples/simple/config.ru +0 -14
- data/examples/simple/publisher.rb +0 -49
- data/examples/simple/qwirk_persist.yml +0 -4
- data/examples/simple/tmp/kahadb/db-1.log +0 -0
- data/examples/simple/tmp/kahadb/db.data +0 -0
- data/examples/simple/tmp/kahadb/db.redo +0 -0
- data/examples/task/README +0 -47
- data/examples/task/config.ru +0 -14
- data/examples/task/foo_worker.rb +0 -10
- data/examples/task/messages.out +0 -1000
- data/examples/task/publisher.rb +0 -25
- data/examples/task/qwirk_persist.yml +0 -5
- data/examples/task/task.rb +0 -36
- data/lib/qwirk/queue_adapter.rb +0 -3
- data/lib/qwirk/queue_adapter/active_mq.rb +0 -13
- data/lib/qwirk/queue_adapter/active_mq/publisher.rb +0 -12
- data/lib/qwirk/queue_adapter/active_mq/worker_config.rb +0 -16
- data/lib/qwirk/queue_adapter/in_mem.rb +0 -7
- data/lib/qwirk/queue_adapter/in_mem/worker_config.rb +0 -59
- data/lib/qwirk/queue_adapter/jms.rb +0 -50
- data/lib/qwirk/queue_adapter/jms/connection.rb +0 -42
- data/lib/qwirk/queue_adapter/jms/consumer.rb +0 -37
- data/lib/qwirk/queue_adapter/jms/publisher.rb +0 -126
- data/lib/qwirk/queue_adapter/jms/worker.rb +0 -89
- data/lib/qwirk/queue_adapter/jms/worker_config.rb +0 -38
- data/lib/qwirk/version.rb +0 -3
- data/lib/qwirk/worker_config.rb +0 -187
@@ -1,89 +0,0 @@
|
|
1
|
-
# Handle Messaging and Queuing using JMS
|
2
|
-
module Qwirk
|
3
|
-
module QueueAdapter
|
4
|
-
module JMS
|
5
|
-
class Worker
|
6
|
-
def initialize(worker_config)
|
7
|
-
@worker_config = worker_config
|
8
|
-
@name = worker_config.parent.name
|
9
|
-
@marshaler = worker_config.parent.marshaler
|
10
|
-
@session = worker_config.connection.create_session
|
11
|
-
@consumer = @session.consumer(worker_config.destination)
|
12
|
-
@session.start
|
13
|
-
end
|
14
|
-
|
15
|
-
def receive_message
|
16
|
-
@consumer.receive
|
17
|
-
end
|
18
|
-
|
19
|
-
def acknowledge_message(msg)
|
20
|
-
msg.acknowledge
|
21
|
-
end
|
22
|
-
|
23
|
-
def send_response(original_message, marshaled_object)
|
24
|
-
do_send_response(@marshaler, original_message, marshaled_object)
|
25
|
-
end
|
26
|
-
|
27
|
-
def send_exception(original_message, e)
|
28
|
-
@string_marshaler ||= MarshalStrategy.find(:string)
|
29
|
-
do_send_response(@string_marshaler, original_message, "Exception: #{e.message}") do |reply_message|
|
30
|
-
reply_message['qwirk:exception'] = Qwirk::RemoteException.new(e).to_hash.to_yaml
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def message_to_object(msg)
|
35
|
-
marshaler = Qwirk::MarshalStrategy.find(msg['qwirk:marshal'] || :ruby)
|
36
|
-
return marshaler.unmarshal(msg.data)
|
37
|
-
end
|
38
|
-
|
39
|
-
def handle_failure(message, fail_queue_name)
|
40
|
-
@session.producer(:queue_name => fail_queue_name) do |producer|
|
41
|
-
# TODO: Can't add attribute to read-only message?
|
42
|
-
#message['qwirk:exception'] = Qwirk::RemoteException.new(e).to_hash.to_yaml
|
43
|
-
producer.send(message)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def stop
|
48
|
-
puts "in jms worker stop"
|
49
|
-
return if @stopped
|
50
|
-
Qwirk.logger.info "Stopping JMS worker #{@name}"
|
51
|
-
# Don't clobber the session before a reply
|
52
|
-
@consumer.close if @consumer
|
53
|
-
@session.close if @session
|
54
|
-
@stopped = true
|
55
|
-
end
|
56
|
-
|
57
|
-
private
|
58
|
-
|
59
|
-
def do_send_response(marshaler, original_message, marshaled_object)
|
60
|
-
return false unless original_message.reply_to
|
61
|
-
begin
|
62
|
-
@session.producer(:destination => original_message.reply_to) do |producer|
|
63
|
-
# For time_to_live and jms_deliver_mode, first use the local response_options if they're' set, otherwise
|
64
|
-
# use the value from the original_message attributes if they're' set
|
65
|
-
time_to_live = @time_to_live || original_message['qwirk:response:time_to_live']
|
66
|
-
persistent = @persistent
|
67
|
-
persistent = (original_message['qwirk:response:persistent'] == 'true') if persistent.nil? && original_message['qwirk:response:persistent']
|
68
|
-
# If persistent isn't set anywhere, then default to true unless time_to_live has been set
|
69
|
-
persistent = !time_to_live if persistent.nil?
|
70
|
-
# The reply is persistent if we explicitly set it or if we don't expire
|
71
|
-
producer.delivery_mode_sym = persistent ? :persistent : :non_persistent
|
72
|
-
producer.time_to_live = time_to_live.to_i if time_to_live
|
73
|
-
reply_message = Qwirk::QueueAdapter::JMS.create_message(@session, marshaled_object, marshaler.marshal_type)
|
74
|
-
reply_message.jms_correlation_id = original_message.jms_message_id
|
75
|
-
reply_message['qwirk:marshal'] = marshaler.to_sym.to_s
|
76
|
-
reply_message['qwirk:worker'] = @name
|
77
|
-
reply_message['QwirkTaskID'] = original_message['QwirkTaskID'] if original_message['QwirkTaskID']
|
78
|
-
yield reply_message if block_given?
|
79
|
-
producer.send(reply_message)
|
80
|
-
end
|
81
|
-
rescue Exception => e
|
82
|
-
Qwirk.logger.error {"Error attempting to send response: #{e.message}\n\t#{e.backtrace.join("\n\t")}"}
|
83
|
-
end
|
84
|
-
return true
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
@@ -1,38 +0,0 @@
|
|
1
|
-
# Handle Messaging and Queuing using JMS
|
2
|
-
module Qwirk
|
3
|
-
module QueueAdapter
|
4
|
-
module JMS
|
5
|
-
class WorkerConfig
|
6
|
-
include Rumx::Bean
|
7
|
-
|
8
|
-
#bean_reader :queue_size, :integer, 'Current count of messages in the queue'
|
9
|
-
|
10
|
-
attr_reader :connection, :parent, :destination, :marshaler, :time_to_live, :persistent, :stopped
|
11
|
-
|
12
|
-
def initialize(queue_adapter, parent, queue_name, topic_name, options, response_options)
|
13
|
-
@connection = queue_adapter.adapter_info
|
14
|
-
@parent = parent
|
15
|
-
@destination = {:queue_name => queue_name} if queue_name
|
16
|
-
@destination = {:topic_name => topic_name} if topic_name
|
17
|
-
# Time in msec until the message gets discarded, should be more than the timeout on the requestor side
|
18
|
-
@time_to_live = response_options[:time_to_live]
|
19
|
-
@persistent = response_options[:persistent]
|
20
|
-
end
|
21
|
-
|
22
|
-
# Default marshal type for the response
|
23
|
-
def default_marshal_sym
|
24
|
-
:ruby
|
25
|
-
end
|
26
|
-
|
27
|
-
def create_worker
|
28
|
-
Worker.new(self)
|
29
|
-
end
|
30
|
-
|
31
|
-
def stop
|
32
|
-
puts "in jms worker config stop"
|
33
|
-
@stopped = true
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
data/lib/qwirk/version.rb
DELETED
data/lib/qwirk/worker_config.rb
DELETED
@@ -1,187 +0,0 @@
|
|
1
|
-
require 'rumx'
|
2
|
-
|
3
|
-
module Qwirk
|
4
|
-
class WorkerConfig
|
5
|
-
include Rumx::Bean
|
6
|
-
|
7
|
-
attr_reader :name, :marshaler
|
8
|
-
|
9
|
-
bean_reader :count, :integer, 'Current number of workers'
|
10
|
-
bean_attr_accessor :min_count, :integer, 'Min number of workers allowed', :config_item => true
|
11
|
-
bean_attr_accessor :max_count, :integer, 'Max number of workers allowed', :config_item => true
|
12
|
-
bean_attr_accessor :idle_worker_timeout, :integer, 'Timeout where an idle worker will be removed from the worker pool and it\'s resources closed (0 for no removal)', :config_item => true
|
13
|
-
bean_attr_accessor :max_read_threshold, :float, 'Threshold where a new worker will be added if none of the workers have had to wait this amount of time on a read', :config_item => true
|
14
|
-
# The adapter refers to the corresponding class in Qwirk::QueueAdapter::<type>::WorkerConfig
|
15
|
-
bean_attr_reader :adapter, :bean, 'Adapter for worker queue interface'
|
16
|
-
bean_attr_reader :timer, :bean, 'Track the times for this worker'
|
17
|
-
bean_attr_accessor :log_times, :boolean, 'Log the times for this worker'
|
18
|
-
|
19
|
-
# Define the default config values for the attributes all workers will share. These will be sent as options to the constructor
|
20
|
-
def self.initial_default_config
|
21
|
-
{:min_count => 0, :max_count => 0, :idle_worker_timeout => 60, :max_read_threshold => 1.0}
|
22
|
-
end
|
23
|
-
|
24
|
-
# Create new WorkerConfig to manage workers of a common class
|
25
|
-
def initialize(queue_adapter, name, manager, worker_class, default_options, options)
|
26
|
-
@name = name
|
27
|
-
@manager = manager
|
28
|
-
@worker_class = worker_class
|
29
|
-
@workers = []
|
30
|
-
@stopped = false
|
31
|
-
@min_count = 0
|
32
|
-
@max_count = 0
|
33
|
-
@index_count = 0
|
34
|
-
@index_mutex = Mutex.new
|
35
|
-
@worker_mutex = Mutex.new
|
36
|
-
@worker_condition = ConditionVariable.new
|
37
|
-
response_options = worker_class.queue_options[:response] || {}
|
38
|
-
@adapter = queue_adapter.create_adapter_worker_config(self, worker_class.queue_name(@name), worker_class.topic_name, worker_class.queue_options, response_options)
|
39
|
-
# Defines how we will marshal the response
|
40
|
-
marshal_sym = (response_options[:marshal] || @adapter.default_marshal_sym)
|
41
|
-
@marshaler = MarshalStrategy.find(marshal_sym)
|
42
|
-
@log_times = queue_adapter.log_times
|
43
|
-
|
44
|
-
#Qwirk.logger.debug { "options=#{options.inspect}" }
|
45
|
-
default_options.each do |key, value|
|
46
|
-
begin
|
47
|
-
send(key.to_s+'=', value)
|
48
|
-
rescue Exception => e
|
49
|
-
# Let config_reader's set a default value
|
50
|
-
begin
|
51
|
-
instance_variable_set("@#{key}", value)
|
52
|
-
rescue Exception => e
|
53
|
-
Qwirk.logger.warn "WARNING: During initialization of #{worker_class.name} config=#{@name}, default assignment of #{key}=#{value} was invalid"
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
# Run the specified options after the default options, so that codependant options don't get overwritten (like min_count/max_count)
|
58
|
-
options.each do |key, value|
|
59
|
-
begin
|
60
|
-
send(key.to_s+'=', value)
|
61
|
-
rescue Exception => e
|
62
|
-
Qwirk.logger.warn "WARNING: During initialization of #{worker_class.name} config=#{@name}, assignment of #{key}=#{value} was invalid"
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def count
|
68
|
-
@worker_mutex.synchronize { return @workers.size }
|
69
|
-
end
|
70
|
-
|
71
|
-
def min_count=(new_min_count)
|
72
|
-
return if @min_count == new_min_count
|
73
|
-
raise "#{@worker_class.name}-#{@name}: Can't change count since we've been stopped" if @stopped
|
74
|
-
Qwirk.logger.info "#{@worker_class.name}: Changing min number of workers from #{@min_count} to #{new_min_count}"
|
75
|
-
self.max_count = new_min_count if @max_count < new_min_count
|
76
|
-
@worker_mutex.synchronize do
|
77
|
-
add_worker while @workers.size < new_min_count
|
78
|
-
@min_count = new_min_count
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
def max_count=(new_max_count)
|
83
|
-
return if @max_count == new_max_count
|
84
|
-
raise "#{@worker_class.name}-#{@name}: Can't change count since we've been stopped" if @stopped
|
85
|
-
Qwirk.logger.info "#{@worker_class.name}: Changing max number of workers from #{@max_count} to #{new_max_count}"
|
86
|
-
self.min_count = new_max_count if @min_count > new_max_count
|
87
|
-
@min_count = 1 if @min_count == 0 && new_max_count > 0
|
88
|
-
@worker_mutex.synchronize do
|
89
|
-
@timer ||= Rumx::Beans::TimerAndError.new
|
90
|
-
if @workers.size > new_max_count
|
91
|
-
@workers[new_max_count..-1].each { |worker| worker.stop }
|
92
|
-
while @workers.size > new_max_count
|
93
|
-
@workers.last.stop
|
94
|
-
@worker_condition.wait(@worker_mutex)
|
95
|
-
end
|
96
|
-
end
|
97
|
-
@max_count = new_max_count
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
def stop
|
102
|
-
Qwirk.logger.debug { "In Base worker_config stop" }
|
103
|
-
# First stop the adapter. For InMem, this will not return until all the messages in the queue have
|
104
|
-
# been processed since these messages are not persistent.
|
105
|
-
@adapter.stop
|
106
|
-
@worker_mutex.synchronize do
|
107
|
-
@workers.each { |worker| worker.stop }
|
108
|
-
while @workers.size > 0
|
109
|
-
@worker_condition.wait(@worker_mutex)
|
110
|
-
end
|
111
|
-
@stopped = true
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
def worker_stopped(worker)
|
116
|
-
remove_worker(worker)
|
117
|
-
end
|
118
|
-
|
119
|
-
# Override rumx bean method
|
120
|
-
def bean_attributes_changed
|
121
|
-
super
|
122
|
-
@manager.save_persist_state
|
123
|
-
end
|
124
|
-
|
125
|
-
def marshal_response(object)
|
126
|
-
@marshaler.marshal(object)
|
127
|
-
end
|
128
|
-
|
129
|
-
def unmarshal_response(marshaled_object)
|
130
|
-
@marshaler.unmarshal(marshaled_object)
|
131
|
-
end
|
132
|
-
|
133
|
-
def periodic_call(poll_time)
|
134
|
-
now = Time.now
|
135
|
-
add_new_worker = true
|
136
|
-
worker_stopped = false
|
137
|
-
@worker_mutex.synchronize do
|
138
|
-
# reverse_each to remove later workers first
|
139
|
-
@workers.reverse_each do |worker|
|
140
|
-
start_worker_time = worker.start_worker_time
|
141
|
-
start_read_time = worker.start_read_time
|
142
|
-
if !start_read_time || (now - start_worker_time) < (poll_time + @max_read_threshold)
|
143
|
-
#Qwirk.logger.debug { "#{self}: Skipping newly created worker" }
|
144
|
-
add_new_worker = false
|
145
|
-
next
|
146
|
-
end
|
147
|
-
end_read_time = worker.start_processing_time
|
148
|
-
# If the processing time is actually from the previous processing, then we're probably still waiting for the read to complete.
|
149
|
-
if !end_read_time || end_read_time < start_read_time
|
150
|
-
if !worker_stopped && @workers.size > @min_count && (now - start_read_time) > @idle_worker_timeout
|
151
|
-
worker.stop
|
152
|
-
worker_stopped = true
|
153
|
-
end
|
154
|
-
end_read_time = now
|
155
|
-
end
|
156
|
-
#Qwirk.logger.debug { "#{self}: start=#{start_read_time} end=#{end_read_time} thres=#{@max_read_threshold} add_new_worker=#{add_new_worker}" }
|
157
|
-
add_new_worker = false if (end_read_time - start_read_time) > @max_read_threshold
|
158
|
-
end
|
159
|
-
add_worker if add_new_worker && @workers.size < @max_count
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
def to_s
|
164
|
-
@name
|
165
|
-
end
|
166
|
-
|
167
|
-
private
|
168
|
-
|
169
|
-
def add_worker
|
170
|
-
worker = @worker_class.new
|
171
|
-
worker.start(@index_count, self)
|
172
|
-
Qwirk.logger.debug {"#{self}: Adding worker #{worker}"}
|
173
|
-
@index_mutex.synchronize { @index_count += 1 }
|
174
|
-
@workers << worker
|
175
|
-
rescue Exception => e
|
176
|
-
Qwirk.logger.error("Unable to add #{@worker_class} worker: #{e.message}\n\t#{e.backtrace.join("\n\t")}")
|
177
|
-
end
|
178
|
-
|
179
|
-
def remove_worker(worker)
|
180
|
-
Qwirk.logger.debug {"#{self}: Deleting worker #{worker}"}
|
181
|
-
@worker_mutex.synchronize do
|
182
|
-
@workers.delete(worker)
|
183
|
-
@worker_condition.broadcast
|
184
|
-
end
|
185
|
-
end
|
186
|
-
end
|
187
|
-
end
|