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.
Files changed (89) hide show
  1. data/README.md +9 -14
  2. data/lib/qwirk.rb +26 -17
  3. data/lib/qwirk/adapter.rb +3 -45
  4. data/lib/qwirk/adapter/base.rb +2 -0
  5. data/lib/qwirk/adapter/base/expanding_worker_config.rb +133 -0
  6. data/lib/qwirk/adapter/base/worker_config.rb +104 -0
  7. data/lib/qwirk/adapter/in_memory.rb +13 -0
  8. data/lib/qwirk/{queue_adapter/in_mem → adapter/in_memory}/factory.rb +2 -2
  9. data/lib/qwirk/{queue_adapter/in_mem → adapter/in_memory}/publisher.rb +4 -4
  10. data/lib/qwirk/{queue_adapter/in_mem → adapter/in_memory}/queue.rb +3 -2
  11. data/lib/qwirk/{queue_adapter/in_mem → adapter/in_memory}/reply_queue.rb +3 -2
  12. data/lib/qwirk/{queue_adapter/in_mem → adapter/in_memory}/topic.rb +2 -2
  13. data/lib/qwirk/{queue_adapter/in_mem → adapter/in_memory}/worker.rb +6 -8
  14. data/lib/qwirk/adapter/in_memory/worker_config.rb +50 -0
  15. data/lib/qwirk/adapter/inline.rb +9 -0
  16. data/lib/qwirk/adapter/inline/publisher.rb +86 -0
  17. data/lib/qwirk/adapter/inline/worker.rb +55 -0
  18. data/lib/qwirk/adapter/inline/worker_config.rb +30 -0
  19. data/lib/qwirk/adapter_factory.rb +48 -0
  20. data/lib/qwirk/base_worker.rb +18 -28
  21. data/lib/qwirk/batch/file_worker.rb +4 -4
  22. data/lib/qwirk/manager.rb +11 -8
  23. data/lib/qwirk/marshal_strategy/none.rb +1 -1
  24. data/lib/qwirk/publish_handle.rb +22 -11
  25. data/lib/qwirk/publisher.rb +9 -9
  26. data/lib/qwirk/{request_worker.rb → reply_worker.rb} +3 -3
  27. data/lib/qwirk/worker.rb +27 -29
  28. data/test/jms_fail_test.rb +11 -11
  29. data/test/jms_requestor_block_test.rb +12 -12
  30. data/test/jms_requestor_test.rb +8 -8
  31. data/test/jms_test.rb +10 -10
  32. metadata +104 -185
  33. data/examples/README +0 -1
  34. data/examples/activemq.xml +0 -84
  35. data/examples/advanced_requestor/README.md +0 -15
  36. data/examples/advanced_requestor/base_request_worker.rb +0 -18
  37. data/examples/advanced_requestor/char_count_worker.rb +0 -16
  38. data/examples/advanced_requestor/config.ru +0 -24
  39. data/examples/advanced_requestor/exception_raiser_worker.rb +0 -17
  40. data/examples/advanced_requestor/length_worker.rb +0 -14
  41. data/examples/advanced_requestor/print_worker.rb +0 -14
  42. data/examples/advanced_requestor/publisher.rb +0 -49
  43. data/examples/advanced_requestor/qwirk.yml +0 -16
  44. data/examples/advanced_requestor/reverse_worker.rb +0 -14
  45. data/examples/advanced_requestor/triple_worker.rb +0 -14
  46. data/examples/batch/my_batch_worker.rb +0 -30
  47. data/examples/batch/my_line_worker.rb +0 -8
  48. data/examples/qwirk.yml +0 -20
  49. data/examples/requestor/README.md +0 -13
  50. data/examples/requestor/config.ru +0 -13
  51. data/examples/requestor/qwirk_persist.yml +0 -5
  52. data/examples/requestor/requestor.rb +0 -68
  53. data/examples/requestor/reverse_echo_worker.rb +0 -15
  54. data/examples/setup.rb +0 -13
  55. data/examples/shared/README.md +0 -24
  56. data/examples/shared/config.ru +0 -13
  57. data/examples/shared/publisher.rb +0 -49
  58. data/examples/shared/qwirk_persist.yml +0 -5
  59. data/examples/shared/shared_worker.rb +0 -16
  60. data/examples/simple/README +0 -53
  61. data/examples/simple/bar_worker.rb +0 -10
  62. data/examples/simple/baz_worker.rb +0 -10
  63. data/examples/simple/config.ru +0 -14
  64. data/examples/simple/publisher.rb +0 -49
  65. data/examples/simple/qwirk_persist.yml +0 -4
  66. data/examples/simple/tmp/kahadb/db-1.log +0 -0
  67. data/examples/simple/tmp/kahadb/db.data +0 -0
  68. data/examples/simple/tmp/kahadb/db.redo +0 -0
  69. data/examples/task/README +0 -47
  70. data/examples/task/config.ru +0 -14
  71. data/examples/task/foo_worker.rb +0 -10
  72. data/examples/task/messages.out +0 -1000
  73. data/examples/task/publisher.rb +0 -25
  74. data/examples/task/qwirk_persist.yml +0 -5
  75. data/examples/task/task.rb +0 -36
  76. data/lib/qwirk/queue_adapter.rb +0 -3
  77. data/lib/qwirk/queue_adapter/active_mq.rb +0 -13
  78. data/lib/qwirk/queue_adapter/active_mq/publisher.rb +0 -12
  79. data/lib/qwirk/queue_adapter/active_mq/worker_config.rb +0 -16
  80. data/lib/qwirk/queue_adapter/in_mem.rb +0 -7
  81. data/lib/qwirk/queue_adapter/in_mem/worker_config.rb +0 -59
  82. data/lib/qwirk/queue_adapter/jms.rb +0 -50
  83. data/lib/qwirk/queue_adapter/jms/connection.rb +0 -42
  84. data/lib/qwirk/queue_adapter/jms/consumer.rb +0 -37
  85. data/lib/qwirk/queue_adapter/jms/publisher.rb +0 -126
  86. data/lib/qwirk/queue_adapter/jms/worker.rb +0 -89
  87. data/lib/qwirk/queue_adapter/jms/worker_config.rb +0 -38
  88. data/lib/qwirk/version.rb +0 -3
  89. 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
@@ -1,3 +0,0 @@
1
- module Qwirk
2
- VERSION = '0.0.1'
3
- end
@@ -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