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 +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
|