micro_q 0.9.5 → 0.9.6

Sign up to get free protection for your applications and to get access to all the features.
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