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 +4 -4
- data/README.md +7 -1
- data/lib/micro_q.rb +5 -1
- data/lib/micro_q/cli.rb +44 -7
- data/lib/micro_q/fetchers/sqs.rb +19 -2
- data/lib/micro_q/manager/default.rb +29 -17
- data/lib/micro_q/middleware/server/retry.rb +23 -3
- data/lib/micro_q/queue/sqs.rb +11 -6
- data/lib/micro_q/sqs_client.rb +7 -0
- data/lib/micro_q/version.rb +1 -1
- data/spec/lib/fetchers/sqs_spec.rb +21 -0
- data/spec/lib/manager/default_spec.rb +92 -2
- data/spec/lib/middleware/server/retry_spec.rb +71 -6
- data/spec/lib/queue/sqs_spec.rb +36 -0
- data/spec/lib/sqs_client_spec.rb +23 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 285d44726c946a46f1781e23c1b96de900a355ce
|
4
|
+
data.tar.gz: 7b57f333f09f40d8d7f2f257c58233269f64b8e4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
data/lib/micro_q.rb
CHANGED
@@ -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
|
|
data/lib/micro_q/cli.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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 =
|
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
|
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
|
data/lib/micro_q/fetchers/sqs.rb
CHANGED
@@ -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(
|
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
|
-
|
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
|
-
|
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 &&
|
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
|
-
|
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 +
|
94
|
+
[MicroQ.config.workers - (workers.size + busy.size), 0].max
|
79
95
|
end
|
80
96
|
|
81
97
|
def kill_all
|
82
|
-
(
|
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
|
-
|
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'] = (
|
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)
|
data/lib/micro_q/queue/sqs.rb
CHANGED
@@ -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(
|
21
|
-
async.sync_push(
|
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']
|
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
|
data/lib/micro_q/sqs_client.rb
CHANGED
@@ -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
|
data/lib/micro_q/version.rb
CHANGED
@@ -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(:
|
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
|
-
|
83
|
-
safe(:call); @payload['retried']['when'].to_i.should == (Time.now + 15).to_i
|
90
|
+
@payload['retried'] = { 'count' => 1 }
|
84
91
|
|
85
|
-
|
86
|
-
safe(:call)
|
87
|
-
|
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'
|
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
|
data/spec/lib/queue/sqs_spec.rb
CHANGED
@@ -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
|
data/spec/lib/sqs_client_spec.rb
CHANGED
@@ -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.
|
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-
|
11
|
+
date: 2013-04-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: celluloid
|