shoryuken 2.0.11 → 3.0.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/.codeclimate.yml +20 -0
- data/.rubocop.yml +8 -2
- data/.travis.yml +7 -5
- data/CHANGELOG.md +127 -10
- data/Gemfile +1 -0
- data/README.md +20 -57
- data/Rakefile +0 -1
- data/bin/cli/base.rb +42 -0
- data/bin/cli/sqs.rb +187 -0
- data/bin/shoryuken +55 -9
- data/examples/default_worker.rb +1 -12
- data/lib/shoryuken/client.rb +3 -25
- data/lib/shoryuken/default_worker_registry.rb +9 -5
- data/lib/shoryuken/environment_loader.rb +29 -67
- data/lib/shoryuken/fetcher.rb +22 -53
- data/lib/shoryuken/launcher.rb +5 -29
- data/lib/shoryuken/manager.rb +77 -180
- data/lib/shoryuken/message.rb +4 -13
- data/lib/shoryuken/middleware/chain.rb +1 -18
- data/lib/shoryuken/middleware/server/auto_extend_visibility.rb +21 -18
- data/lib/shoryuken/middleware/server/exponential_backoff_retry.rb +26 -19
- data/lib/shoryuken/polling.rb +204 -0
- data/lib/shoryuken/processor.rb +9 -14
- data/lib/shoryuken/queue.rb +36 -38
- data/lib/shoryuken/runner.rb +143 -0
- data/lib/shoryuken/util.rb +3 -9
- data/lib/shoryuken/version.rb +1 -1
- data/lib/shoryuken/worker.rb +1 -1
- data/lib/shoryuken.rb +78 -39
- data/shoryuken.gemspec +6 -6
- data/spec/integration/launcher_spec.rb +4 -3
- data/spec/shoryuken/client_spec.rb +2 -43
- data/spec/shoryuken/default_worker_registry_spec.rb +12 -10
- data/spec/shoryuken/environment_loader_spec.rb +34 -0
- data/spec/shoryuken/fetcher_spec.rb +18 -52
- data/spec/shoryuken/manager_spec.rb +56 -97
- data/spec/shoryuken/middleware/chain_spec.rb +0 -24
- data/spec/shoryuken/middleware/server/auto_delete_spec.rb +2 -2
- data/spec/shoryuken/middleware/server/auto_extend_visibility_spec.rb +7 -3
- data/spec/shoryuken/middleware/server/exponential_backoff_retry_spec.rb +56 -33
- data/spec/shoryuken/polling_spec.rb +239 -0
- data/spec/shoryuken/processor_spec.rb +7 -5
- data/spec/shoryuken/queue_spec.rb +110 -63
- data/spec/shoryuken/{cli_spec.rb → runner_spec.rb} +10 -24
- data/spec/shoryuken_spec.rb +13 -1
- data/spec/spec_helper.rb +8 -20
- data/test_workers/endless_interruptive_worker.rb +41 -0
- data/test_workers/endless_uninterruptive_worker.rb +44 -0
- metadata +34 -35
- data/.hound.yml +0 -6
- data/lib/shoryuken/cli.rb +0 -210
- data/lib/shoryuken/sns_arn.rb +0 -27
- data/lib/shoryuken/topic.rb +0 -17
- data/spec/shoryuken/sns_arn_spec.rb +0 -42
- data/spec/shoryuken/topic_spec.rb +0 -32
- data/spec/shoryuken_endpoint.yml +0 -6
- /data/{LICENSE.txt → LICENSE} +0 -0
|
@@ -44,28 +44,4 @@ describe Shoryuken::Middleware::Chain do
|
|
|
44
44
|
expect(final_action).to eq nil
|
|
45
45
|
expect(recorder).to eq []
|
|
46
46
|
end
|
|
47
|
-
|
|
48
|
-
class DeprecatedMiddleware
|
|
49
|
-
def call(worker_instance, queue, sqs_msg)
|
|
50
|
-
@@success = true
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def self.success?
|
|
54
|
-
!!@@success
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
it 'patches deprecated middleware' do
|
|
59
|
-
subject.clear
|
|
60
|
-
|
|
61
|
-
expect(Shoryuken.logger).to receive(:warn) do |&block|
|
|
62
|
-
expect(block.call).to eq('[DEPRECATION] DeprecatedMiddleware#call(worker_instance, queue, sqs_msg) is deprecated. Please use DeprecatedMiddleware#call(worker_instance, queue, sqs_msg, body)')
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
subject.add DeprecatedMiddleware
|
|
66
|
-
|
|
67
|
-
subject.invoke TestWorker, 'test', double('SQS msg', body: 'test'), 'test'
|
|
68
|
-
|
|
69
|
-
expect(DeprecatedMiddleware.success?).to eq true
|
|
70
|
-
end
|
|
71
47
|
end
|
|
@@ -55,8 +55,8 @@ describe Shoryuken::Middleware::Server::AutoDelete do
|
|
|
55
55
|
expect(sqs_queue).to_not receive(:delete_messages)
|
|
56
56
|
|
|
57
57
|
expect {
|
|
58
|
-
subject.call(TestWorker.new, queue, sqs_msg, sqs_msg.body) { raise '
|
|
59
|
-
}.to raise_error(
|
|
58
|
+
subject.call(TestWorker.new, queue, sqs_msg, sqs_msg.body) { raise 'failed' }
|
|
59
|
+
}.to raise_error('failed')
|
|
60
60
|
end
|
|
61
61
|
end
|
|
62
62
|
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
|
|
3
|
-
describe Shoryuken::Middleware::Server::AutoExtendVisibility do
|
|
3
|
+
RSpec.describe Shoryuken::Middleware::Server::AutoExtendVisibility do
|
|
4
4
|
let(:queue) { 'default' }
|
|
5
5
|
let(:visibility_timeout) { 3 }
|
|
6
6
|
let(:extend_upfront) { 1 }
|
|
@@ -12,8 +12,6 @@ describe Shoryuken::Middleware::Server::AutoExtendVisibility do
|
|
|
12
12
|
|
|
13
13
|
# We need to run our worker inside actor context.
|
|
14
14
|
class Runner
|
|
15
|
-
include Celluloid
|
|
16
|
-
|
|
17
15
|
def run_and_sleep(worker, queue, sqs_msg, interval)
|
|
18
16
|
Shoryuken::Middleware::Server::AutoExtendVisibility.new.call(worker, queue, sqs_msg, sqs_msg.body) do
|
|
19
17
|
sleep interval
|
|
@@ -34,6 +32,12 @@ describe Shoryuken::Middleware::Server::AutoExtendVisibility do
|
|
|
34
32
|
stub_const('Shoryuken::Middleware::Server::AutoExtendVisibility::EXTEND_UPFRONT_SECONDS', extend_upfront)
|
|
35
33
|
end
|
|
36
34
|
|
|
35
|
+
context 'when batch worker' do
|
|
36
|
+
it 'yields' do
|
|
37
|
+
expect { |b| subject.call(nil, nil, [], nil, &b) }.to yield_control
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
37
41
|
it 'extends message visibility if jobs takes a long time' do
|
|
38
42
|
TestWorker.get_shoryuken_options['auto_visibility_timeout'] = true
|
|
39
43
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# rubocop:disable Metrics/BlockLength, Metrics/BlockDelimiters
|
|
4
|
+
RSpec.describe Shoryuken::Middleware::Server::ExponentialBackoffRetry do
|
|
4
5
|
let(:queue) { 'default' }
|
|
5
6
|
let(:sqs_queue) { double Shoryuken::Queue }
|
|
6
7
|
let(:sqs_msg) { double Shoryuken::Message, queue_url: queue, body: 'test', receipt_handle: SecureRandom.uuid,
|
|
@@ -10,8 +11,14 @@ describe Shoryuken::Middleware::Server::ExponentialBackoffRetry do
|
|
|
10
11
|
allow(Shoryuken::Client).to receive(:queues).with(queue).and_return(sqs_queue)
|
|
11
12
|
end
|
|
12
13
|
|
|
13
|
-
context 'when
|
|
14
|
-
it '
|
|
14
|
+
context 'when batch worker' do
|
|
15
|
+
it 'yields' do
|
|
16
|
+
expect { |b| subject.call(nil, nil, [], nil, &b) }.to yield_control
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
context 'when no exception' do
|
|
21
|
+
it 'does not retry' do
|
|
15
22
|
TestWorker.get_shoryuken_options['retry_intervals'] = [300, 1800]
|
|
16
23
|
|
|
17
24
|
expect(sqs_msg).not_to receive(:change_visibility)
|
|
@@ -20,62 +27,78 @@ describe Shoryuken::Middleware::Server::ExponentialBackoffRetry do
|
|
|
20
27
|
end
|
|
21
28
|
end
|
|
22
29
|
|
|
23
|
-
context 'when
|
|
30
|
+
context 'when an error' do
|
|
31
|
+
context "and retry_intervals isn't set" do
|
|
32
|
+
it 'does not retry' do
|
|
33
|
+
expect(sqs_msg).not_to receive(:change_visibility)
|
|
24
34
|
|
|
25
|
-
|
|
26
|
-
|
|
35
|
+
expect {
|
|
36
|
+
subject.call(TestWorker.new, queue, sqs_msg, sqs_msg.body) { raise 'Error' }
|
|
37
|
+
}.to raise_error(RuntimeError, 'Error')
|
|
38
|
+
end
|
|
39
|
+
end
|
|
27
40
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
41
|
+
context 'and retry_intervals is a lambda' do
|
|
42
|
+
it 'retries' do
|
|
43
|
+
TestWorker.get_shoryuken_options['retry_intervals'] = ->(_attempts) { 500 }
|
|
44
|
+
|
|
45
|
+
allow(sqs_msg).to receive(:queue) { sqs_queue }
|
|
46
|
+
expect(sqs_msg).to receive(:change_visibility).with(visibility_timeout: 500)
|
|
47
|
+
|
|
48
|
+
expect { subject.call(TestWorker.new, queue, sqs_msg, sqs_msg.body) { raise 'failed' } }.not_to raise_error
|
|
49
|
+
end
|
|
31
50
|
end
|
|
32
51
|
|
|
33
|
-
|
|
34
|
-
|
|
52
|
+
context 'and retry_intervals is empty' do
|
|
53
|
+
it 'does not retry' do
|
|
54
|
+
TestWorker.get_shoryuken_options['retry_intervals'] = []
|
|
35
55
|
|
|
36
|
-
|
|
56
|
+
expect(sqs_msg).not_to receive(:change_visibility)
|
|
37
57
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
58
|
+
expect {
|
|
59
|
+
subject.call(TestWorker.new, queue, sqs_msg, sqs_msg.body) { raise 'Error' }
|
|
60
|
+
}.to raise_error(RuntimeError, 'Error')
|
|
61
|
+
end
|
|
41
62
|
end
|
|
42
63
|
|
|
43
|
-
it '
|
|
64
|
+
it 'uses first interval ' do
|
|
44
65
|
TestWorker.get_shoryuken_options['retry_intervals'] = [300, 1800]
|
|
45
66
|
|
|
46
|
-
allow(sqs_msg).to receive(:queue){ sqs_queue }
|
|
67
|
+
allow(sqs_msg).to receive(:queue) { sqs_queue }
|
|
47
68
|
expect(sqs_msg).to receive(:change_visibility).with(visibility_timeout: 300)
|
|
48
69
|
|
|
49
|
-
expect { subject.call(TestWorker.new, queue, sqs_msg, sqs_msg.body) { raise } }.not_to raise_error
|
|
70
|
+
expect { subject.call(TestWorker.new, queue, sqs_msg, sqs_msg.body) { raise 'failed' } }.not_to raise_error
|
|
50
71
|
end
|
|
51
72
|
|
|
52
|
-
it '
|
|
73
|
+
it 'uses matching interval' do
|
|
53
74
|
TestWorker.get_shoryuken_options['retry_intervals'] = [300, 1800]
|
|
54
75
|
|
|
55
|
-
allow(sqs_msg).to receive(:attributes){ {'ApproximateReceiveCount' => 2 } }
|
|
56
|
-
allow(sqs_msg).to receive(:queue){ sqs_queue }
|
|
76
|
+
allow(sqs_msg).to receive(:attributes) { { 'ApproximateReceiveCount' => 2 } }
|
|
77
|
+
allow(sqs_msg).to receive(:queue) { sqs_queue }
|
|
57
78
|
expect(sqs_msg).to receive(:change_visibility).with(visibility_timeout: 1800)
|
|
58
79
|
|
|
59
|
-
expect { subject.call(TestWorker.new, queue, sqs_msg, sqs_msg.body) { raise } }.not_to raise_error
|
|
80
|
+
expect { subject.call(TestWorker.new, queue, sqs_msg, sqs_msg.body) { raise 'failed' } }.not_to raise_error
|
|
60
81
|
end
|
|
61
82
|
|
|
62
|
-
|
|
63
|
-
|
|
83
|
+
context 'when attempts exceeds retry_intervals' do
|
|
84
|
+
it 'uses last interval' do
|
|
85
|
+
TestWorker.get_shoryuken_options['retry_intervals'] = [300, 1800]
|
|
64
86
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
87
|
+
allow(sqs_msg).to receive(:attributes) { { 'ApproximateReceiveCount' => 3 } }
|
|
88
|
+
allow(sqs_msg).to receive(:queue) { sqs_queue }
|
|
89
|
+
expect(sqs_msg).to receive(:change_visibility).with(visibility_timeout: 1800)
|
|
68
90
|
|
|
69
|
-
|
|
91
|
+
expect { subject.call(TestWorker.new, queue, sqs_msg, sqs_msg.body) { raise 'failed' } }.not_to raise_error
|
|
92
|
+
end
|
|
70
93
|
end
|
|
71
94
|
|
|
72
|
-
it 'limits the visibility timeout to 12 hours
|
|
73
|
-
TestWorker.get_shoryuken_options['retry_intervals'] = [
|
|
95
|
+
it 'limits the visibility timeout to 12 hours' do
|
|
96
|
+
TestWorker.get_shoryuken_options['retry_intervals'] = [86_400]
|
|
74
97
|
|
|
75
|
-
allow(sqs_msg).to receive(:queue){ sqs_queue }
|
|
76
|
-
expect(sqs_msg).to receive(:change_visibility).with(visibility_timeout:
|
|
98
|
+
allow(sqs_msg).to receive(:queue) { sqs_queue }
|
|
99
|
+
expect(sqs_msg).to receive(:change_visibility).with(visibility_timeout: 43_198)
|
|
77
100
|
|
|
78
|
-
expect { subject.call(TestWorker.new, queue, sqs_msg, sqs_msg.body) { raise } }.not_to raise_error
|
|
101
|
+
expect { subject.call(TestWorker.new, queue, sqs_msg, sqs_msg.body) { raise 'failed' } }.not_to raise_error
|
|
79
102
|
end
|
|
80
103
|
end
|
|
81
104
|
end
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'shoryuken/polling'
|
|
3
|
+
|
|
4
|
+
describe Shoryuken::Polling::WeightedRoundRobin do
|
|
5
|
+
let(:queue1) { 'shoryuken' }
|
|
6
|
+
let(:queue2) { 'uppercut' }
|
|
7
|
+
let(:queues) { Array.new }
|
|
8
|
+
subject { Shoryuken::Polling::WeightedRoundRobin.new(queues) }
|
|
9
|
+
|
|
10
|
+
describe '#next_queue' do
|
|
11
|
+
it 'cycles' do
|
|
12
|
+
# [shoryuken, 2]
|
|
13
|
+
# [uppercut, 1]
|
|
14
|
+
queues << queue1
|
|
15
|
+
queues << queue1
|
|
16
|
+
queues << queue2
|
|
17
|
+
|
|
18
|
+
expect(subject.next_queue).to eq(queue1)
|
|
19
|
+
expect(subject.next_queue).to eq(queue2)
|
|
20
|
+
expect(subject.next_queue).to eq(queue1)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it 'returns nil if there are no active queues' do
|
|
24
|
+
expect(subject.next_queue).to eq(nil)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it 'unpauses queues whose pause is expired' do
|
|
28
|
+
# [shoryuken, 2]
|
|
29
|
+
# [uppercut, 1]
|
|
30
|
+
queues << queue1
|
|
31
|
+
queues << queue1
|
|
32
|
+
queues << queue2
|
|
33
|
+
|
|
34
|
+
allow(subject).to receive(:delay).and_return(10)
|
|
35
|
+
|
|
36
|
+
now = Time.now
|
|
37
|
+
allow(Time).to receive(:now).and_return(now)
|
|
38
|
+
|
|
39
|
+
# pause the first queue
|
|
40
|
+
subject.messages_found(queue1, 0)
|
|
41
|
+
expect(subject.next_queue).to eq(queue2)
|
|
42
|
+
|
|
43
|
+
now += 5
|
|
44
|
+
allow(Time).to receive(:now).and_return(now)
|
|
45
|
+
|
|
46
|
+
# pause the second queue
|
|
47
|
+
subject.messages_found(queue2, 0)
|
|
48
|
+
expect(subject.next_queue).to eq(nil)
|
|
49
|
+
|
|
50
|
+
# queue1 should be unpaused now
|
|
51
|
+
now += 6
|
|
52
|
+
allow(Time).to receive(:now).and_return(now)
|
|
53
|
+
expect(subject.next_queue).to eq(queue1)
|
|
54
|
+
|
|
55
|
+
# queue1 should be unpaused and added to the end of queues now
|
|
56
|
+
now += 6
|
|
57
|
+
allow(Time).to receive(:now).and_return(now)
|
|
58
|
+
expect(subject.next_queue).to eq(queue1)
|
|
59
|
+
expect(subject.next_queue).to eq(queue2)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
describe '#messages_found' do
|
|
64
|
+
it 'pauses a queue if there are no messages found' do
|
|
65
|
+
# [shoryuken, 2]
|
|
66
|
+
# [uppercut, 1]
|
|
67
|
+
queues << queue1
|
|
68
|
+
queues << queue1
|
|
69
|
+
queues << queue2
|
|
70
|
+
|
|
71
|
+
expect(subject).to receive(:pause).with(queue1).and_call_original
|
|
72
|
+
subject.messages_found(queue1, 0)
|
|
73
|
+
expect(subject.instance_variable_get(:@queues)).to eq([queue2])
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it 'increased the weight if message is found' do
|
|
77
|
+
# [shoryuken, 2]
|
|
78
|
+
# [uppercut, 1]
|
|
79
|
+
queues << queue1
|
|
80
|
+
queues << queue1
|
|
81
|
+
queues << queue2
|
|
82
|
+
|
|
83
|
+
expect(subject.instance_variable_get(:@queues)).to eq([queue1, queue2])
|
|
84
|
+
subject.messages_found(queue1, 1)
|
|
85
|
+
expect(subject.instance_variable_get(:@queues)).to eq([queue1, queue2, queue1])
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it 'respects the maximum queue weight' do
|
|
89
|
+
# [shoryuken, 2]
|
|
90
|
+
# [uppercut, 1]
|
|
91
|
+
queues << queue1
|
|
92
|
+
queues << queue1
|
|
93
|
+
queues << queue2
|
|
94
|
+
|
|
95
|
+
subject.messages_found(queue1, 1)
|
|
96
|
+
subject.messages_found(queue1, 1)
|
|
97
|
+
expect(subject.instance_variable_get(:@queues)).to eq([queue1, queue2, queue1])
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
describe Shoryuken::Polling::StrictPriority do
|
|
103
|
+
let(:queue1) { 'shoryuken' }
|
|
104
|
+
let(:queue2) { 'uppercut' }
|
|
105
|
+
let(:queue3) { 'other' }
|
|
106
|
+
let(:queues) { Array.new }
|
|
107
|
+
subject { Shoryuken::Polling::StrictPriority.new(queues) }
|
|
108
|
+
|
|
109
|
+
describe '#next_queue' do
|
|
110
|
+
it 'cycles when declared desc' do
|
|
111
|
+
# [shoryuken, 2]
|
|
112
|
+
# [uppercut, 1]
|
|
113
|
+
queues << queue1
|
|
114
|
+
queues << queue1
|
|
115
|
+
queues << queue2
|
|
116
|
+
|
|
117
|
+
expect(subject.next_queue).to eq(queue1)
|
|
118
|
+
expect(subject.next_queue).to eq(queue2)
|
|
119
|
+
expect(subject.next_queue).to eq(queue1)
|
|
120
|
+
expect(subject.next_queue).to eq(queue2)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it 'cycles when declared asc' do
|
|
124
|
+
# [uppercut, 1]
|
|
125
|
+
# [shoryuken, 2]
|
|
126
|
+
queues << queue2
|
|
127
|
+
queues << queue1
|
|
128
|
+
queues << queue1
|
|
129
|
+
|
|
130
|
+
expect(subject.next_queue).to eq(queue1)
|
|
131
|
+
expect(subject.next_queue).to eq(queue2)
|
|
132
|
+
expect(subject.next_queue).to eq(queue1)
|
|
133
|
+
expect(subject.next_queue).to eq(queue2)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it 'returns nil if there are no active queues' do
|
|
137
|
+
expect(subject.next_queue).to eq(nil)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
it 'unpauses queues whose pause is expired' do
|
|
141
|
+
# [shoryuken, 3]
|
|
142
|
+
# [uppercut, 2]
|
|
143
|
+
# [other, 1]
|
|
144
|
+
queues << queue1
|
|
145
|
+
queues << queue1
|
|
146
|
+
queues << queue1
|
|
147
|
+
queues << queue2
|
|
148
|
+
queues << queue2
|
|
149
|
+
queues << queue3
|
|
150
|
+
|
|
151
|
+
allow(subject).to receive(:delay).and_return(10)
|
|
152
|
+
|
|
153
|
+
now = Time.now
|
|
154
|
+
allow(Time).to receive(:now).and_return(now)
|
|
155
|
+
|
|
156
|
+
# pause the second queue, see it loop between 1 and 3
|
|
157
|
+
subject.messages_found(queue2, 0)
|
|
158
|
+
expect(subject.next_queue).to eq(queue1)
|
|
159
|
+
expect(subject.next_queue).to eq(queue3)
|
|
160
|
+
expect(subject.next_queue).to eq(queue1)
|
|
161
|
+
|
|
162
|
+
now += 5
|
|
163
|
+
allow(Time).to receive(:now).and_return(now)
|
|
164
|
+
|
|
165
|
+
# pause the first queue, see it repeat 3
|
|
166
|
+
subject.messages_found(queue1, 0)
|
|
167
|
+
expect(subject.next_queue).to eq(queue3)
|
|
168
|
+
expect(subject.next_queue).to eq(queue3)
|
|
169
|
+
|
|
170
|
+
# pause the third queue, see it have nothing
|
|
171
|
+
subject.messages_found(queue3, 0)
|
|
172
|
+
expect(subject.next_queue).to eq(nil)
|
|
173
|
+
|
|
174
|
+
# unpause queue 2
|
|
175
|
+
now += 6
|
|
176
|
+
allow(Time).to receive(:now).and_return(now)
|
|
177
|
+
expect(subject.next_queue).to eq(queue2)
|
|
178
|
+
|
|
179
|
+
# unpause queues 1 and 3
|
|
180
|
+
now += 6
|
|
181
|
+
allow(Time).to receive(:now).and_return(now)
|
|
182
|
+
expect(subject.next_queue).to eq(queue1)
|
|
183
|
+
expect(subject.next_queue).to eq(queue2)
|
|
184
|
+
expect(subject.next_queue).to eq(queue3)
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
describe '#messages_found' do
|
|
189
|
+
it 'pauses a queue if there are no messages found' do
|
|
190
|
+
# [shoryuken, 2]
|
|
191
|
+
# [uppercut, 1]
|
|
192
|
+
queues << queue1
|
|
193
|
+
queues << queue1
|
|
194
|
+
queues << queue2
|
|
195
|
+
|
|
196
|
+
expect(subject.active_queues).to eq([[queue1, 2], [queue2, 1]])
|
|
197
|
+
expect(subject).to receive(:pause).with(queue1).and_call_original
|
|
198
|
+
subject.messages_found(queue1, 0)
|
|
199
|
+
expect(subject.active_queues).to eq([[queue2, 1]])
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
it 'continues to queue the highest priority queue if messages are found' do
|
|
203
|
+
# [shoryuken, 3]
|
|
204
|
+
# [uppercut, 2]
|
|
205
|
+
# [other, 1]
|
|
206
|
+
queues << queue1
|
|
207
|
+
queues << queue1
|
|
208
|
+
queues << queue1
|
|
209
|
+
queues << queue2
|
|
210
|
+
queues << queue2
|
|
211
|
+
queues << queue3
|
|
212
|
+
|
|
213
|
+
expect(subject.next_queue).to eq(queue1)
|
|
214
|
+
subject.messages_found(queue1, 1)
|
|
215
|
+
expect(subject.next_queue).to eq(queue1)
|
|
216
|
+
subject.messages_found(queue1, 1)
|
|
217
|
+
expect(subject.next_queue).to eq(queue1)
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
it 'resets the priorities if messages are found part way' do
|
|
221
|
+
# [shoryuken, 3]
|
|
222
|
+
# [uppercut, 2]
|
|
223
|
+
# [other, 1]
|
|
224
|
+
queues << queue1
|
|
225
|
+
queues << queue1
|
|
226
|
+
queues << queue1
|
|
227
|
+
queues << queue2
|
|
228
|
+
queues << queue2
|
|
229
|
+
queues << queue3
|
|
230
|
+
|
|
231
|
+
expect(subject.next_queue).to eq(queue1)
|
|
232
|
+
expect(subject.next_queue).to eq(queue2)
|
|
233
|
+
subject.messages_found(queue2, 1)
|
|
234
|
+
expect(subject.next_queue).to eq(queue1)
|
|
235
|
+
expect(subject.next_queue).to eq(queue2)
|
|
236
|
+
expect(subject.next_queue).to eq(queue3)
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
end
|
|
@@ -99,6 +99,7 @@ RSpec.describe Shoryuken::Processor do
|
|
|
99
99
|
end
|
|
100
100
|
|
|
101
101
|
it 'logs the error' do
|
|
102
|
+
expect(manager).to receive(:processor_failed)
|
|
102
103
|
expect(subject.logger).to receive(:error) do |&block|
|
|
103
104
|
expect(block.call).
|
|
104
105
|
to include("unexpected token at 'invalid json'\nbody_parser: json\nsqs_msg.body: invalid json")
|
|
@@ -108,6 +109,7 @@ RSpec.describe Shoryuken::Processor do
|
|
|
108
109
|
end
|
|
109
110
|
|
|
110
111
|
it 're raises the error' do
|
|
112
|
+
expect(manager).to receive(:processor_failed)
|
|
111
113
|
expect { subject.process(queue, sqs_msg) }.
|
|
112
114
|
to raise_error(JSON::ParserError, /unexpected token at 'invalid json'/)
|
|
113
115
|
end
|
|
@@ -169,7 +171,7 @@ RSpec.describe Shoryuken::Processor do
|
|
|
169
171
|
end
|
|
170
172
|
|
|
171
173
|
it 'invokes middleware' do
|
|
172
|
-
expect(manager).to receive(:processor_done).with(queue
|
|
174
|
+
expect(manager).to receive(:processor_done).with(queue)
|
|
173
175
|
|
|
174
176
|
expect_any_instance_of(WorkerCalledMiddlewareWorker).to receive(:perform).with(sqs_msg, sqs_msg.body)
|
|
175
177
|
expect_any_instance_of(WorkerCalledMiddlewareWorker).to receive(:called).with(sqs_msg, queue)
|
|
@@ -199,7 +201,7 @@ RSpec.describe Shoryuken::Processor do
|
|
|
199
201
|
end
|
|
200
202
|
|
|
201
203
|
it "doesn't invoke middleware" do
|
|
202
|
-
expect(manager).to receive(:processor_done).with(queue
|
|
204
|
+
expect(manager).to receive(:processor_done).with(queue)
|
|
203
205
|
|
|
204
206
|
expect_any_instance_of(WorkerCalledMiddlewareWorker).to receive(:perform).with(sqs_msg, sqs_msg.body)
|
|
205
207
|
expect_any_instance_of(WorkerCalledMiddlewareWorker).to_not receive(:called).with(sqs_msg, queue)
|
|
@@ -212,7 +214,7 @@ RSpec.describe Shoryuken::Processor do
|
|
|
212
214
|
it 'performs with delete' do
|
|
213
215
|
TestWorker.get_shoryuken_options['auto_delete'] = true
|
|
214
216
|
|
|
215
|
-
expect(manager).to receive(:processor_done).with(queue
|
|
217
|
+
expect(manager).to receive(:processor_done).with(queue)
|
|
216
218
|
|
|
217
219
|
expect_any_instance_of(TestWorker).to receive(:perform).with(sqs_msg, sqs_msg.body)
|
|
218
220
|
|
|
@@ -224,7 +226,7 @@ RSpec.describe Shoryuken::Processor do
|
|
|
224
226
|
it 'performs without delete' do
|
|
225
227
|
TestWorker.get_shoryuken_options['auto_delete'] = false
|
|
226
228
|
|
|
227
|
-
expect(manager).to receive(:processor_done).with(queue
|
|
229
|
+
expect(manager).to receive(:processor_done).with(queue)
|
|
228
230
|
|
|
229
231
|
expect_any_instance_of(TestWorker).to receive(:perform).with(sqs_msg, sqs_msg.body)
|
|
230
232
|
|
|
@@ -249,7 +251,7 @@ RSpec.describe Shoryuken::Processor do
|
|
|
249
251
|
it 'performs without delete' do
|
|
250
252
|
Shoryuken.worker_registry.clear # unregister TestWorker
|
|
251
253
|
|
|
252
|
-
expect(manager).to receive(:processor_done).with(queue
|
|
254
|
+
expect(manager).to receive(:processor_done).with(queue)
|
|
253
255
|
|
|
254
256
|
expect_any_instance_of(TestWorker).to receive(:perform).with(sqs_msg, sqs_msg.body)
|
|
255
257
|
|