qwirk 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|