micro_q 0.9.5 → 0.9.6

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0ce5b78c270ba5ed5145cc8ebdb0fc8155cafaf8
4
- data.tar.gz: caafc65fac3531906ec9d37e5f475e8d5c1bb560
3
+ metadata.gz: 285d44726c946a46f1781e23c1b96de900a355ce
4
+ data.tar.gz: 7b57f333f09f40d8d7f2f257c58233269f64b8e4
5
5
  SHA512:
6
- metadata.gz: f1c625a377f9c3abd1b242f9e270e1a0acbad20edcde60e03f4f9cccee1b86236278cff444ebd057629bb206ea728346b3ec79249090cb8543ff3474faa2e63c
7
- data.tar.gz: 17e5790a270f4476dfee6a93476b094609b6b9dbc5fa90f7da6fb83219477c0a6faad6db112b1ec1ef90bdb60883dd4e09660ee2942a90581e38f07d704c9106
6
+ metadata.gz: 8cfa95f52fe7d18cce6cb9fe1790bb970f59c9cd6fc2011705d4b0471dd5d104b6a2631a0ebaf93921ea1d5a5f3d71abad283113542e24f538af797a1ac7f8c3
7
+ data.tar.gz: eea48e42cc2c63d1d051cb784ca044340e58ae458f50fda04026661bf75997f05ab5b9c6532823944f6022ebeb4243b4a5d480fdd78911a4db9048be8dd9e60f
data/README.md CHANGED
@@ -39,7 +39,7 @@ end
39
39
  ###Simple
40
40
 
41
41
  ```ruby
42
- Called on the class invoked on an instance.
42
+ # Called on the class invoked on an instance.
43
43
 
44
44
  MyWorker.perform_async
45
45
  MyWorker.update_async(:user_id => user.id)
@@ -102,9 +102,15 @@ MicroQ.configure do |config|
102
102
  config.queue = MicroQ::Queue::Sqs
103
103
  config.aws = { :key => 'YOUR KEY', :secret => 'YOUR SECRET' }
104
104
  end
105
+ ```
105
106
 
106
107
  **Note that when using the SQS Queue only the MicroQ's started via command-line will actually process messages**
107
108
 
109
+ Start via the command line to process messages `microq`
110
+
111
+ This queue also sets up thress named queues `:low`, `:default` and `:critical`
112
+
113
+ ```ruby
108
114
  # Then just use the queues in your workers
109
115
  class SomeWorker
110
116
  worker :queue => :critical
@@ -33,6 +33,10 @@ module MicroQ
33
33
  manager.queue.push(*args)
34
34
  end
35
35
 
36
+ def self.queue_only?
37
+ @queue_only ||= MicroQ.config.sqs? && !MicroQ.config.worker_mode?
38
+ end
39
+
36
40
  private
37
41
 
38
42
  def self.manager
@@ -44,7 +48,7 @@ module MicroQ
44
48
  end
45
49
 
46
50
  def self.clear
47
- @config = @manager = nil
51
+ @config = @manager = @queue_only = nil
48
52
  end
49
53
  end
50
54
 
@@ -14,41 +14,67 @@ module MicroQ
14
14
  opts = Slop.parse do
15
15
  banner 'Usage: microq [options]'
16
16
 
17
+ on 'h', 'This menu'
18
+ on 'help', 'This menu'
19
+ on 't=', 'The queue type to process [redis, sqs]'
20
+ on 'type=', 'The queue type to process [redis, sqs]'
17
21
  on 'r=', 'The path to the rails application'
18
22
  on 'require=', 'The path to the rails application'
19
23
  on 'w=', 'The number of worker threads'
20
24
  on 'workers=', 'The number of worker threads'
21
25
  end
22
26
 
27
+ (puts usage; exit) if opts[:help] || opts[:h]
28
+
23
29
  @workers = opts[:workers] || opts[:w]
24
- @require = opts[:require] || opts[:r]
30
+ @require = opts[:require] || opts[:r] || 'config/environment.rb'
31
+ @mode = (opts[:type] || opts[:t] || 'sqs'.tap { puts 'Defaulting to sqs type' }).downcase
25
32
  end
26
33
 
27
34
  def verify!
28
- raise "Need a valid path to a rails application, you gave us #{@require}\n" unless /environment\.rb/ === @require || File.exist?("#{@require}/config/application.rb")
35
+ unless File.exist?(@require) || File.exist?("#{@require}/config/application.rb")
36
+ puts 'Typically the -r option is simply the base path of the application'
37
+ puts 'This could be `pwd` or something special in production...'
38
+ puts "We tried both File.exist?(opts[:require]) and File.exist?(opts[:require] + 'config/application.rb')"
39
+ raise "MicroQ requires a valid rails application path via the -r option\n"
40
+ end
29
41
  end
30
42
 
31
43
  def setup
32
- puts 'Requiring rails...'
44
+ puts 'Requiring rails application...'
45
+
33
46
  require 'rails'
34
47
 
35
- puts 'Requiring rails application...'
36
48
  if File.directory?(@require)
37
49
  require File.expand_path("#{@require}/config/environment.rb")
38
50
  else
39
51
  require @require
40
52
  end
41
53
 
54
+ Rails.application.eager_load!
55
+
42
56
  aws_keys = MicroQ.config.aws.try(:keys) || []
43
- raise 'SQS mode requires an aws :key and :secret see https://github.com/bnorton/micro_q/wiki/Named-Queues' unless aws_keys.include?(:key) && aws_keys.include?(:secret)
57
+
58
+ queue = if @mode == 'sqs'
59
+ raise 'SQS mode requires an aws :key and :secret see https://github.com/bnorton/micro_q/wiki/Named-Queues' unless aws_keys.include?(:key) && aws_keys.include?(:secret)
60
+
61
+ MicroQ::Queue::Sqs
62
+ elsif @mode == 'redis'
63
+ puts 'Using redis config' + MicroQ.config.redis.map {|(k,v)| "#{k}=#{v}" }.join(' ')
64
+
65
+ MicroQ::Queue::Redis
66
+ else
67
+ raise 'Only Redis and SQS mode are supported via the command line.'
68
+ end
44
69
 
45
70
  MicroQ.configure do |config|
46
- config.queue = MicroQ::Queue::Sqs # set workers after since this must set workers=0 internally
71
+ config.queue = queue # set workers after assigning the queue since this sets workers=0 internally for the sqs queue
47
72
  config.workers = @workers.to_i if @workers
48
73
  config['worker_mode?'] = true
49
74
  end
50
75
 
51
- puts "Running micro_q in SQS mode with #{MicroQ.config.workers} workers... Hit ctl+c to stop...\n"
76
+ puts "Running micro_q in #{@mode.upcase} mode with #{MicroQ.config.workers} workers..."
77
+ puts 'ctl+c to shutdown...'
52
78
  MicroQ.start
53
79
 
54
80
  sleep
@@ -56,5 +82,16 @@ module MicroQ
56
82
  puts 'Exiting via interrupt'
57
83
  exit(1)
58
84
  end
85
+
86
+ def usage
87
+ <<-USAGE
88
+ Run microq with messages enqueued to and dequeued from SQS or Redis.
89
+ Usage: microq [options]
90
+ -h, --help This menu.
91
+ -t, --type [redis, sqs] The type of queue being utilized (either Redis or SQS)
92
+ -r, --require The path the rails app's config/environment.rb file.
93
+ -w, --workers The number of workers for this process.
94
+ USAGE
95
+ end
59
96
  end
60
97
  end
@@ -9,6 +9,10 @@ module MicroQ
9
9
  @manager = manager
10
10
  end
11
11
 
12
+ ##
13
+ # Long poll the SQS messages API and if there are messages
14
+ # then fetch more right away. Send messages to the manager
15
+ # when they return from the API
12
16
  def start
13
17
  defer do
14
18
  client.messages.tap do |messages|
@@ -16,22 +20,35 @@ module MicroQ
16
20
  end
17
21
  end
18
22
 
19
- after(2) { start }
23
+ after(SHORT_DELAY) { start }
20
24
  end
21
25
 
26
+ ##
27
+ # Add the message to the sqs queue
28
+ # Respect the maximum amount of time that a message can
29
+ # be delayed (900 seconds).
30
+ #
22
31
  def add_message(message, time=nil)
23
- message['run_at'] = time.to_f if time
32
+ message['run_at'] = [time.to_f, (Time.now + 900).to_i].min if time
24
33
 
25
34
  defer do
26
35
  client.messages_create(message)
27
36
  end
28
37
  end
29
38
 
39
+ def remove_message(message)
40
+ defer do
41
+ client.messages_delete(message)
42
+ end
43
+ end
44
+
30
45
  private
31
46
 
32
47
  def client
33
48
  @client ||= MicroQ::SqsClient.new(name)
34
49
  end
50
+
51
+ SHORT_DELAY = 2
35
52
  end
36
53
  end
37
54
  end
@@ -20,19 +20,16 @@ module MicroQ
20
20
  # Invoke this when the Queue or Worker pool dies
21
21
  exit_handler :reinitialize
22
22
 
23
- attr_reader :queue, :workers
23
+ attr_reader :queue, :workers, :busy, :current
24
24
 
25
25
  def start
26
- return if queue_only?
26
+ return if MicroQ.queue_only?
27
27
 
28
28
  count = workers.size
29
29
 
30
30
  if (messages = queue.dequeue(count)).any?
31
31
  messages.each do |message|
32
- worker = workers.pop
33
- @busy << worker
34
-
35
- worker.perform!(message)
32
+ work_on(message)
36
33
  end
37
34
  end
38
35
 
@@ -40,22 +37,41 @@ module MicroQ
40
37
  end
41
38
 
42
39
  def work_done(worker)
43
- @busy.delete(worker)
40
+ message = current.delete(worker)
41
+ queue.finished!(message) if queue.respond_to?(:finished)
42
+
43
+ busy.delete(worker)
44
44
  workers.push(worker)
45
45
  end
46
46
 
47
+ def work_on(message)
48
+ worker = workers.pop
49
+ busy << worker
50
+
51
+ current[worker] = message
52
+
53
+ worker.perform!(message)
54
+ end
55
+
47
56
  ##
48
57
  # Handle init/death of the Queue or the Worker pool
58
+ # When a worker dies the args are (#<Actor ...>, #<Exception>)
49
59
  #
50
- def reinitialize(*)
60
+ def reinitialize(*args)
51
61
  kill_all and return if self.class.shutdown?
52
62
 
53
- unless @queue && @queue.alive?
63
+ unless @queue && queue.alive?
54
64
  @queue = MicroQ.config.queue.new_link
55
65
  end
56
66
 
57
67
  @busy ||= []
58
68
  @workers ||= []
69
+ @current ||= {}
70
+
71
+ if args.any?
72
+ message = current.delete(args.first)
73
+ queue.finished!(message) if queue.respond_to?(:finished)
74
+ end
59
75
 
60
76
  build_missing_workers
61
77
  end
@@ -64,10 +80,10 @@ module MicroQ
64
80
 
65
81
  # Don't shrink the pool if the config changes
66
82
  def build_missing_workers
67
- return if queue_only?
83
+ return if MicroQ.queue_only?
68
84
 
69
85
  workers.select!(&:alive?)
70
- @busy.select!(&:alive?)
86
+ busy.select!(&:alive?)
71
87
 
72
88
  missing_worker_count.times do
73
89
  workers << MicroQ.config.worker.new_link(current_actor)
@@ -75,15 +91,11 @@ module MicroQ
75
91
  end
76
92
 
77
93
  def missing_worker_count
78
- [MicroQ.config.workers - (workers.size + @busy.size), 0].max
94
+ [MicroQ.config.workers - (workers.size + busy.size), 0].max
79
95
  end
80
96
 
81
97
  def kill_all
82
- (@workers + @busy).each {|w| w.terminate if w.alive? }
83
- end
84
-
85
- def queue_only?
86
- @queue_only ||= MicroQ.config.sqs? && !MicroQ.config.worker_mode?
98
+ (workers + busy).each {|w| w.terminate if w.alive? }
87
99
  end
88
100
 
89
101
  def self.shutdown?
@@ -23,19 +23,39 @@ module MicroQ
23
23
  retried!(message)
24
24
  stats(message)
25
25
 
26
- MicroQ.push(message, message['retried'])
26
+ unless message['retried']['count'] > retry_count(message)
27
+ MicroQ.push(message, message['retried'])
28
+ end
27
29
 
28
30
  raise e
29
31
  end
30
32
 
31
33
  private
32
34
 
35
+ def retry_count(msg)
36
+ [Fixnum, String].include?(msg['retry'].class) ? msg['retry'].to_i : 25
37
+ end
38
+
33
39
  def retried!(msg)
34
40
  msg['retried'] ||= { 'count' => 0 }
35
41
 
36
- msg['retried']['count'] += 1
37
42
  msg['retried']['at'] = Time.now
38
- msg['retried']['when'] = (Time.now + 15).to_f
43
+ msg['retried']['when'] = next_retry(msg['retried'])
44
+ msg['retried']['count'] += 1
45
+ end
46
+
47
+ ## On retry:
48
+ # 0-3 random interval up to 12 seconds
49
+ # 4-13 retry after an exponential amount of time
50
+ # otherwise retry after 8 hours
51
+ def next_retry(retried)
52
+ count = retried['count']
53
+
54
+ (Time.now + case count
55
+ when 0..3 then rand(2..12)
56
+ when 4..13 then (count** 4)
57
+ else 8*60*60
58
+ end).to_f
39
59
  end
40
60
 
41
61
  def stats(msg)
@@ -11,14 +11,14 @@ module MicroQ
11
11
  def initialize
12
12
  @lock = Mutex.new
13
13
 
14
- @messages, @entries, @later = [], [], []
14
+ @messages, @fetchers, @entries, @later = [], [], [], []
15
15
  @fetcher_map = {}
16
16
 
17
17
  build_missing_fetchers
18
18
  end
19
19
 
20
- def push(item)
21
- async.sync_push(item)
20
+ def push(*args)
21
+ async.sync_push(*args)
22
22
  end
23
23
 
24
24
  def sync_push(item, options={})
@@ -26,7 +26,7 @@ module MicroQ
26
26
  item['class'] = item['class'].to_s
27
27
 
28
28
  MicroQ.middleware.client.call(item, options) do
29
- args, queue_name = [item], verify_queue(item['queue'].to_s)
29
+ args, queue_name = [item], verify_queue(item['queue'])
30
30
 
31
31
  if (time = options['when'])
32
32
  args << time.to_f
@@ -52,8 +52,13 @@ module MicroQ
52
52
  end
53
53
  end
54
54
 
55
+ def finished(item)
56
+ queue_name = verify_queue(item['queue'])
57
+ @fetcher_map[queue_name].remove_message(item)
58
+ end
59
+
55
60
  def verify_queue(name)
56
- QUEUES_KEYS.include?(name) ? name : 'default'
61
+ QUEUES_KEYS.include?(name.to_s) ? name.to_s : 'default'
57
62
  end
58
63
 
59
64
  def self.shutdown!
@@ -73,7 +78,7 @@ module MicroQ
73
78
  ((existing = @fetcher_map[name]) && existing.alive? && existing) ||
74
79
  MicroQ::Fetcher::Sqs.new_link(name, current_actor).tap do |fetcher|
75
80
  @fetcher_map[name] = fetcher
76
- fetcher.start!
81
+ fetcher.start! unless MicroQ.queue_only?
77
82
  end
78
83
  end
79
84
  end
@@ -35,6 +35,13 @@ module MicroQ
35
35
  client.send_message(attrs)[:message_id]
36
36
  end
37
37
 
38
+ def messages_delete(message)
39
+ client.delete_message(
40
+ :queue_url => message['sqs_queue'],
41
+ :receipt_handle => message['sqs_handle']
42
+ )
43
+ end
44
+
38
45
  private
39
46
 
40
47
  def client
@@ -1,7 +1,7 @@
1
1
  module MicroQ
2
2
  MAJOR = 0
3
3
  MINOR = 9
4
- POINT = 5
4
+ POINT = 6
5
5
 
6
6
  VERSION = [MAJOR, MINOR, POINT].join('.')
7
7
  end
@@ -76,6 +76,27 @@ describe MicroQ::Fetcher::Sqs do
76
76
 
77
77
  add_message
78
78
  end
79
+
80
+ describe 'when the time is too far in the future' do
81
+ let(:add_message) { subject.add_message(message, Time.now.to_i + 1000) }
82
+
83
+ it 'should truncate to 900 seconds from now' do
84
+ @client.should_receive(:messages_create).with(message.merge('run_at' => Time.now.to_i + 900))
85
+
86
+ add_message
87
+ end
88
+ end
89
+ end
90
+ end
91
+
92
+ describe '#remove_message' do
93
+ let(:message) { {'class' => 'FooBar'} }
94
+ let(:remove_message) { subject.remove_message(message) }
95
+
96
+ it 'should create the message' do
97
+ @client.should_receive(:messages_delete).with(message)
98
+
99
+ remove_message
79
100
  end
80
101
  end
81
102
  end
@@ -83,6 +83,13 @@ describe MicroQ::Manager::Default do
83
83
  subject.start
84
84
  end
85
85
 
86
+ it 'should add the items to the currently working items' do
87
+ subject.start
88
+
89
+ subject.current[@worker1].should == @other_item
90
+ subject.current[@worker2].should == @item
91
+ end
92
+
86
93
  describe 'when the manager is in SQS mode' do
87
94
  before do
88
95
  MicroQ.config['sqs?'] = true
@@ -118,10 +125,12 @@ describe MicroQ::Manager::Default do
118
125
  end
119
126
 
120
127
  describe '#reinitialize' do
121
- let(:death) { -> { subject.reinitialize } }
128
+ let(:current) { subject.current }
129
+
130
+ let(:death) { -> { subject.reinitialize(@worker2, Exception.new('worker2 crashed')) } }
122
131
 
123
132
  before do
124
- @queue = mock(MicroQ::Queue::Default, :alive? => true, :dequeue => [])
133
+ @queue = mock(MicroQ::Queue::Default, :alive? => true, :dequeue => [], :finished! => nil, :respond_to? => true)
125
134
  MicroQ::Queue::Default.stub(:new_link).and_return(@queue)
126
135
 
127
136
  @worker1 = mock(MicroQ::Worker::Standard, :alive? => true, :perform! => nil)
@@ -178,7 +187,10 @@ describe MicroQ::Manager::Default do
178
187
  end
179
188
 
180
189
  describe 'when a busy worker has died' do
190
+ let(:message) { mock('message') }
191
+
181
192
  before do
193
+ current[@worker2] = message
182
194
  subject.wrapped_object.instance_variable_set(:@busy, [@worker2])
183
195
  end
184
196
 
@@ -199,6 +211,31 @@ describe MicroQ::Manager::Default do
199
211
 
200
212
  subject.workers.should == [@worker1, @new_worker2]
201
213
  end
214
+
215
+ it 'should remove the worker from current' do
216
+ current.should have_key(@worker2)
217
+ death.call
218
+
219
+ current.should_not have_key(@worker2)
220
+ end
221
+
222
+ it 'should finish the message with the queue' do
223
+ @queue.should_receive(:finished!).with(message)
224
+
225
+ death.call
226
+ end
227
+
228
+ describe 'when the queue does not respond to finished' do
229
+ before do
230
+ @queue.stub(:respond_to?).with(:finished).and_return(false)
231
+ end
232
+
233
+ it 'should not call it' do
234
+ @queue.should_not_receive(:finished!)
235
+
236
+ death.call
237
+ end
238
+ end
202
239
  end
203
240
 
204
241
  describe 'when in SQS mode' do
@@ -215,4 +252,57 @@ describe MicroQ::Manager::Default do
215
252
  end
216
253
  end
217
254
  end
255
+
256
+ describe '#work_done' do
257
+ let(:message) { mock('message') }
258
+ let(:current) { subject.current }
259
+
260
+ let(:work_done) { subject.work_done(@worker) }
261
+
262
+ before do
263
+ @worker = mock('worker')
264
+ @queue = mock(MicroQ::Queue::Default, :respond_to? => true, :finished! => nil)
265
+ MicroQ::Queue::Default.stub(:new_link).and_return(@queue)
266
+
267
+ subject.wrapped_object.instance_variable_set(:@busy, [@worker])
268
+ current[@worker] = message
269
+ end
270
+
271
+ it 'should remove the worker from busy' do
272
+ work_done
273
+
274
+ subject.busy.should == []
275
+ end
276
+
277
+ it 'should add the worker to workers' do
278
+ work_done
279
+
280
+ subject.workers.should include(@worker)
281
+ end
282
+
283
+ it 'should remove the worker from current' do
284
+ current.should have_key(@worker)
285
+ work_done
286
+
287
+ current.should_not have_key(@worker)
288
+ end
289
+
290
+ it 'should finish the message with the queue' do
291
+ @queue.should_receive(:finished!).with(message)
292
+
293
+ work_done
294
+ end
295
+
296
+ describe 'when the queue does not respond to finished' do
297
+ before do
298
+ @queue.stub(:respond_to?).with(:finished).and_return(false)
299
+ end
300
+
301
+ it 'should not call it' do
302
+ @queue.should_not_receive(:finished!)
303
+
304
+ work_done
305
+ end
306
+ end
307
+ end
218
308
  end
@@ -34,6 +34,14 @@ describe MicroQ::Middleware::Server::Retry, :middleware => true do
34
34
  call
35
35
  }.to raise_error(Exception, 'an exception')
36
36
  end
37
+
38
+ it 'should not push the message' do
39
+ MicroQ.should_not_receive(:push)
40
+
41
+ expect {
42
+ call
43
+ }.to raise_error(Exception, 'an exception')
44
+ end
37
45
  end
38
46
 
39
47
  describe 'when retry is enabled' do
@@ -79,12 +87,15 @@ describe MicroQ::Middleware::Server::Retry, :middleware => true do
79
87
  end
80
88
 
81
89
  it 'should update the retry when time' do
82
- Timecop.freeze(DateTime.now) do
83
- safe(:call); @payload['retried']['when'].to_i.should == (Time.now + 15).to_i
90
+ @payload['retried'] = { 'count' => 1 }
84
91
 
85
- Timecop.travel(100)
86
- safe(:call); @payload['retried']['when'].to_i.should == (Time.now + 15).to_i
87
- end
92
+ expect {
93
+ safe(:call)
94
+ }.to change { @payload['retried']['when'] }
95
+
96
+ expect {
97
+ safe(:call)
98
+ }.to change { @payload['retried']['when'] }
88
99
  end
89
100
 
90
101
  it 'should set the last retry time' do
@@ -105,10 +116,64 @@ describe MicroQ::Middleware::Server::Retry, :middleware => true do
105
116
 
106
117
  it 'should enqueue for the next retry time' do
107
118
  Timecop.freeze do
108
- MicroQ.should_receive(:push).with(anything, hash_including('when' => (Time.now + 15).to_f))
119
+ MicroQ.should_receive(:push).with(anything, hash_including('when'))
120
+
121
+ safe(:call)
122
+ end
123
+ end
124
+
125
+ describe 'when the message has retried 25 times' do
126
+ before do
127
+ @payload['retried'] = { 'count' => 25 }
128
+ end
129
+
130
+ it 'should not push the message' do
131
+ MicroQ.should_not_receive(:push)
132
+
133
+ expect {
134
+ call
135
+ }.to raise_error(Exception, 'an exception')
136
+ end
137
+ end
138
+
139
+ describe 'when the message should retry 10 times' do
140
+ before do
141
+ @payload['retry'] = 10
142
+ end
143
+
144
+ it 'should retry the message' do
145
+ MicroQ.should_receive(:push)
109
146
 
110
147
  safe(:call)
111
148
  end
149
+
150
+ describe 'when the message has retried 10 times' do
151
+ before do
152
+ @payload['retried'] = { 'count' => 10 }
153
+ end
154
+
155
+ it 'should not push the message' do
156
+ MicroQ.should_not_receive(:push)
157
+
158
+ expect {
159
+ call
160
+ }.to raise_error(Exception, 'an exception')
161
+ end
162
+
163
+ describe 'when the retry count is a string' do
164
+ before do
165
+ @payload['retry'] = '10'
166
+ end
167
+
168
+ it 'should not push the message' do
169
+ MicroQ.should_not_receive(:push)
170
+
171
+ expect {
172
+ call
173
+ }.to raise_error(Exception, 'an exception')
174
+ end
175
+ end
176
+ end
112
177
  end
113
178
  end
114
179
  end
@@ -30,6 +30,18 @@ describe MicroQ::Queue::Sqs do
30
30
  it 'should have the fetchers' do
31
31
  subject.fetchers.uniq.should == [@fetcher]
32
32
  end
33
+
34
+ describe 'when we are in queue only mode' do
35
+ before do
36
+ MicroQ.stub(:queue_only? => true)
37
+ end
38
+
39
+ it 'should not start the fetcher' do
40
+ @fetcher.should_not_receive(:start!)
41
+
42
+ subject
43
+ end
44
+ end
33
45
  end
34
46
 
35
47
  describe '#receive_messages' do
@@ -203,4 +215,28 @@ describe MicroQ::Queue::Sqs do
203
215
  end
204
216
  end
205
217
  end
218
+
219
+ describe '#finished' do
220
+ before do
221
+ @fetchers = [:low, :default, :critical].collect do |name|
222
+ mock('MicroQ::Fetcher::Sqs : ' + name.to_s, :start! => nil).tap do |fetcher|
223
+ MicroQ::Fetcher::Sqs.stub(:new_link).with(name.to_s, anything).and_return(fetcher)
224
+ end
225
+ end
226
+ end
227
+
228
+ [:low, :default, :critical].each_with_index do |name, i|
229
+ describe "when the message has a queue named #{name}" do
230
+ before do
231
+ item['queue'] = name
232
+ end
233
+
234
+ it 'should create the message on the right queue' do
235
+ @fetchers[i].should_receive(:remove_message).with(item)
236
+
237
+ subject.finished(item)
238
+ end
239
+ end
240
+ end
241
+ end
206
242
  end
@@ -163,4 +163,27 @@ describe MicroQ::SqsClient, :aws => true do
163
163
  end
164
164
  end
165
165
  end
166
+
167
+ describe '#messages_delete' do
168
+ let(:message) { { 'sqs_handle' => 'handle-123', 'sqs_queue' => 'http://654.queue' } }
169
+ let(:messages_delete) { subject.messages_delete(message) }
170
+
171
+ it 'should delete the message' do
172
+ @client.should_receive(:delete_message)
173
+
174
+ messages_delete
175
+ end
176
+
177
+ it 'should have the queue url' do
178
+ @client.should_receive(:delete_message).with(hash_including(:queue_url => 'http://654.queue'))
179
+
180
+ messages_delete
181
+ end
182
+
183
+ it 'should have the message handle' do
184
+ @client.should_receive(:delete_message).with(hash_including(:receipt_handle => 'handle-123'))
185
+
186
+ messages_delete
187
+ end
188
+ end
166
189
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: micro_q
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.5
4
+ version: 0.9.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Norton
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-04-04 00:00:00.000000000 Z
11
+ date: 2013-04-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: celluloid