shoryuken 3.0.6 → 4.0.0
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/.rubocop.yml +90 -24
- data/.travis.yml +17 -5
- data/CHANGELOG.md +265 -62
- data/Gemfile +9 -1
- data/Gemfile.aws-sdk-core-v2 +13 -0
- data/README.md +19 -113
- data/Rakefile +1 -1
- data/bin/cli/base.rb +0 -3
- data/bin/cli/sqs.rb +42 -16
- data/bin/shoryuken +4 -9
- data/examples/bootstrap_queues.rb +3 -3
- data/examples/default_worker.rb +2 -2
- data/lib/shoryuken/body_parser.rb +27 -0
- data/lib/shoryuken/client.rb +6 -2
- data/lib/shoryuken/core_ext.rb +1 -1
- data/lib/shoryuken/default_worker_registry.rb +2 -2
- data/lib/shoryuken/environment_loader.rb +60 -24
- data/lib/shoryuken/extensions/active_job_adapter.rb +21 -11
- data/lib/shoryuken/fetcher.rb +58 -19
- data/lib/shoryuken/launcher.rb +70 -7
- data/lib/shoryuken/logging.rb +1 -6
- data/lib/shoryuken/manager.rb +50 -80
- data/lib/shoryuken/middleware/chain.rb +4 -0
- data/lib/shoryuken/middleware/server/active_record.rb +1 -1
- data/lib/shoryuken/middleware/server/auto_delete.rb +4 -9
- data/lib/shoryuken/middleware/server/auto_extend_visibility.rb +6 -9
- data/lib/shoryuken/middleware/server/exponential_backoff_retry.rb +9 -3
- data/lib/shoryuken/middleware/server/timing.rb +12 -16
- data/lib/shoryuken/options.rb +225 -0
- data/lib/shoryuken/polling/base.rb +67 -0
- data/lib/shoryuken/polling/strict_priority.rb +77 -0
- data/lib/shoryuken/polling/weighted_round_robin.rb +66 -0
- data/lib/shoryuken/processor.rb +30 -39
- data/lib/shoryuken/queue.rb +41 -10
- data/lib/shoryuken/runner.rb +13 -17
- data/lib/shoryuken/util.rb +3 -3
- data/lib/shoryuken/version.rb +1 -1
- data/lib/shoryuken/worker/default_executor.rb +33 -0
- data/lib/shoryuken/worker/inline_executor.rb +37 -0
- data/lib/shoryuken/worker.rb +76 -31
- data/lib/shoryuken/worker_registry.rb +4 -4
- data/lib/shoryuken.rb +54 -173
- data/shoryuken.gemspec +6 -6
- data/spec/integration/launcher_spec.rb +14 -8
- data/spec/shoryuken/body_parser_spec.rb +89 -0
- data/spec/shoryuken/client_spec.rb +1 -1
- data/spec/shoryuken/core_ext_spec.rb +6 -6
- data/spec/shoryuken/default_worker_registry_spec.rb +2 -4
- data/spec/shoryuken/environment_loader_spec.rb +32 -12
- data/spec/shoryuken/extensions/active_job_adapter_spec.rb +64 -0
- data/spec/shoryuken/fetcher_spec.rb +101 -18
- data/spec/shoryuken/manager_spec.rb +54 -26
- data/spec/shoryuken/middleware/chain_spec.rb +17 -5
- data/spec/shoryuken/middleware/server/auto_delete_spec.rb +9 -7
- data/spec/shoryuken/middleware/server/auto_extend_visibility_spec.rb +4 -4
- data/spec/shoryuken/middleware/server/exponential_backoff_retry_spec.rb +6 -4
- data/spec/shoryuken/middleware/server/timing_spec.rb +5 -3
- data/spec/shoryuken/options_spec.rb +180 -0
- data/spec/shoryuken/{polling_spec.rb → polling/strict_priority_spec.rb} +2 -101
- data/spec/shoryuken/polling/weighted_round_robin_spec.rb +99 -0
- data/spec/shoryuken/processor_spec.rb +26 -127
- data/spec/shoryuken/queue_spec.rb +115 -41
- data/spec/shoryuken/runner_spec.rb +3 -4
- data/spec/shoryuken/util_spec.rb +24 -0
- data/spec/shoryuken/worker/default_executor_spec.rb +105 -0
- data/spec/shoryuken/worker/inline_executor_spec.rb +49 -0
- data/spec/shoryuken/worker_spec.rb +35 -96
- data/spec/shoryuken_spec.rb +0 -59
- data/spec/spec_helper.rb +14 -3
- data/test_workers/endless_interruptive_worker.rb +2 -2
- data/test_workers/endless_uninterruptive_worker.rb +4 -4
- metadata +31 -12
- data/lib/shoryuken/polling.rb +0 -204
|
@@ -1,22 +1,73 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# rubocop:disable Metrics/BlockLength
|
|
4
|
+
RSpec.describe Shoryuken::Queue do
|
|
4
5
|
let(:credentials) { Aws::Credentials.new('access_key_id', 'secret_access_key') }
|
|
5
6
|
let(:sqs) { Aws::SQS::Client.new(stub_responses: true, credentials: credentials) }
|
|
6
7
|
let(:queue_name) { 'shoryuken' }
|
|
7
|
-
let(:queue_url) {
|
|
8
|
+
let(:queue_url) { "https://sqs.eu-west-1.amazonaws.com:6059/0123456789/#{queue_name}" }
|
|
8
9
|
|
|
9
10
|
subject { described_class.new(sqs, queue_name) }
|
|
10
|
-
|
|
11
|
+
|
|
12
|
+
before do
|
|
11
13
|
# Required as Aws::SQS::Client.get_queue_url returns 'String' when responses are stubbed,
|
|
12
14
|
# which is not accepted by Aws::SQS::Client.get_queue_attributes for :queue_name parameter.
|
|
13
15
|
allow(subject).to receive(:url).and_return(queue_url)
|
|
14
|
-
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
describe '#new' do
|
|
19
|
+
context 'when queue URL supplied' do
|
|
20
|
+
it 'instantiates by URL and validate the URL' do
|
|
21
|
+
expect_any_instance_of(described_class).to receive(:fifo?).and_return(false)
|
|
22
|
+
|
|
23
|
+
subject = described_class.new(sqs, queue_url)
|
|
24
|
+
|
|
25
|
+
expect(subject.name).to eq(queue_name)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
context 'when queue name supplied' do
|
|
30
|
+
subject { described_class.new(sqs, queue_name) }
|
|
31
|
+
|
|
32
|
+
specify do
|
|
33
|
+
expect(subject.name).to eq(queue_name)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
describe '#delete_messages' do
|
|
39
|
+
let(:entries) do
|
|
40
|
+
[
|
|
41
|
+
{ id: '1', receipt_handle: '1' },
|
|
42
|
+
{ id: '2', receipt_handle: '2' }
|
|
43
|
+
]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it 'deletes' do
|
|
47
|
+
expect(sqs).to receive(:delete_message_batch).with(entries: entries, queue_url: queue_url).and_return(double(failed: []))
|
|
48
|
+
|
|
49
|
+
subject.delete_messages(entries: entries)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
context 'when it fails' do
|
|
53
|
+
it 'logs the reason' do
|
|
54
|
+
failure = double(id: 'id', code: 'code', message: '...', sender_fault: false)
|
|
55
|
+
logger = double 'Logger'
|
|
56
|
+
|
|
57
|
+
expect(sqs).to(
|
|
58
|
+
receive(:delete_message_batch).with(entries: entries, queue_url: queue_url).and_return(double(failed: [failure]))
|
|
59
|
+
)
|
|
60
|
+
expect(subject).to receive(:logger).and_return(logger)
|
|
61
|
+
expect(logger).to receive(:error)
|
|
62
|
+
|
|
63
|
+
subject.delete_messages(entries: entries)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
15
67
|
|
|
16
68
|
describe '#send_message' do
|
|
17
|
-
before {
|
|
18
|
-
|
|
19
|
-
}
|
|
69
|
+
before { allow(subject).to receive(:fifo?).and_return(false) }
|
|
70
|
+
|
|
20
71
|
it 'accepts SQS request parameters' do
|
|
21
72
|
# https://docs.aws.amazon.com/sdkforruby/api/Aws/SQS/Client.html#send_message-instance_method
|
|
22
73
|
expect(sqs).to receive(:send_message).with(hash_including(message_body: 'msg1'))
|
|
@@ -65,36 +116,30 @@ describe Shoryuken::Queue do
|
|
|
65
116
|
end
|
|
66
117
|
|
|
67
118
|
describe '#send_messages' do
|
|
68
|
-
before {
|
|
69
|
-
|
|
70
|
-
}
|
|
119
|
+
before { allow(subject).to receive(:fifo?).and_return(false) }
|
|
120
|
+
|
|
71
121
|
it 'accepts SQS request parameters' do
|
|
72
122
|
# https://docs.aws.amazon.com/sdkforruby/api/Aws/SQS/Client.html#send_message_batch-instance_method
|
|
73
|
-
expect(sqs).to
|
|
123
|
+
expect(sqs).to(
|
|
124
|
+
receive(:send_message_batch).with(hash_including(entries: [{ id: '0', message_body: 'msg1' }, { id: '1', message_body: 'msg2' }]))
|
|
125
|
+
)
|
|
74
126
|
|
|
75
|
-
subject.send_messages(entries: [{id: '0', message_body: 'msg1'}, {id: '1', message_body: 'msg2'}])
|
|
127
|
+
subject.send_messages(entries: [{ id: '0', message_body: 'msg1' }, { id: '1', message_body: 'msg2' }])
|
|
76
128
|
end
|
|
77
129
|
|
|
78
130
|
it 'accepts an array of messages' do
|
|
79
|
-
options = { entries: [
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
{ id: '1',
|
|
84
|
-
message_body: 'msg2',
|
|
85
|
-
delay_seconds: 1,
|
|
86
|
-
message_attributes: { attr: 'attr2' } }] }
|
|
87
|
-
|
|
131
|
+
options = { entries: [
|
|
132
|
+
{ id: '0', message_body: 'msg1', delay_seconds: 1, message_attributes: { attr: 'attr1' } },
|
|
133
|
+
{ id: '1', message_body: 'msg2', delay_seconds: 1, message_attributes: { attr: 'attr2' } }
|
|
134
|
+
] }
|
|
88
135
|
expect(sqs).to receive(:send_message_batch).with(hash_including(options))
|
|
89
136
|
|
|
90
|
-
subject.send_messages(
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
message_attributes: { attr: 'attr2' }
|
|
97
|
-
}])
|
|
137
|
+
subject.send_messages(
|
|
138
|
+
[
|
|
139
|
+
{ message_body: 'msg1', delay_seconds: 1, message_attributes: { attr: 'attr1' } },
|
|
140
|
+
{ message_body: 'msg2', delay_seconds: 1, message_attributes: { attr: 'attr2' } }
|
|
141
|
+
]
|
|
142
|
+
)
|
|
98
143
|
end
|
|
99
144
|
|
|
100
145
|
context 'when FIFO' do
|
|
@@ -124,40 +169,69 @@ describe Shoryuken::Queue do
|
|
|
124
169
|
expect(first_entry[:message_deduplication_id]).to eq 'my id'
|
|
125
170
|
end
|
|
126
171
|
|
|
127
|
-
subject.send_messages(
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
172
|
+
subject.send_messages(
|
|
173
|
+
[
|
|
174
|
+
{ message_body: 'msg1',
|
|
175
|
+
message_attributes: { attr: 'attr1' },
|
|
176
|
+
message_group_id: 'my group',
|
|
177
|
+
message_deduplication_id: 'my id' }
|
|
178
|
+
]
|
|
179
|
+
)
|
|
131
180
|
end
|
|
132
181
|
end
|
|
133
182
|
end
|
|
134
183
|
|
|
135
184
|
it 'accepts an array of string' do
|
|
136
|
-
expect(sqs).to
|
|
185
|
+
expect(sqs).to(
|
|
186
|
+
receive(:send_message_batch).with(
|
|
187
|
+
hash_including(entries: [{ id: '0', message_body: 'msg1' }, { id: '1', message_body: 'msg2' }])
|
|
188
|
+
)
|
|
189
|
+
)
|
|
137
190
|
|
|
138
|
-
subject.send_messages(%w
|
|
191
|
+
subject.send_messages(%w[msg1 msg2])
|
|
139
192
|
end
|
|
140
193
|
end
|
|
141
194
|
|
|
142
195
|
describe '#fifo?' do
|
|
196
|
+
let(:attribute_response) { double 'Aws::SQS::Types::GetQueueAttributesResponse' }
|
|
143
197
|
before do
|
|
144
|
-
attribute_response
|
|
145
|
-
|
|
146
|
-
|
|
198
|
+
allow(attribute_response).to(
|
|
199
|
+
receive(:attributes).and_return('FifoQueue' => fifo.to_s, 'ContentBasedDeduplication' => 'true')
|
|
200
|
+
)
|
|
147
201
|
allow(subject).to receive(:url).and_return(queue_url)
|
|
148
|
-
allow(sqs).to
|
|
202
|
+
allow(sqs).to(
|
|
203
|
+
receive(:get_queue_attributes).with(queue_url: queue_url, attribute_names: ['All']).and_return(attribute_response)
|
|
204
|
+
)
|
|
149
205
|
end
|
|
150
206
|
|
|
151
207
|
context 'when queue is FIFO' do
|
|
152
208
|
let(:fifo) { true }
|
|
153
209
|
|
|
154
|
-
|
|
210
|
+
specify { expect(subject.fifo?).to be }
|
|
211
|
+
|
|
212
|
+
it 'memoizes response' do
|
|
213
|
+
expect(sqs).to(
|
|
214
|
+
receive(:get_queue_attributes).with(queue_url: queue_url, attribute_names: ['All']).and_return(attribute_response)
|
|
215
|
+
).exactly(1).times
|
|
216
|
+
|
|
217
|
+
subject.fifo?
|
|
218
|
+
subject.fifo?
|
|
219
|
+
end
|
|
155
220
|
end
|
|
156
221
|
|
|
157
222
|
context 'when queue is not FIFO' do
|
|
158
223
|
let(:fifo) { false }
|
|
159
224
|
|
|
160
|
-
|
|
225
|
+
specify { expect(subject.fifo?).to_not be }
|
|
226
|
+
|
|
227
|
+
it 'memoizes response' do
|
|
228
|
+
expect(sqs).to(
|
|
229
|
+
receive(:get_queue_attributes).with(queue_url: queue_url, attribute_names: ['All']).and_return(attribute_response)
|
|
230
|
+
).exactly(1).times
|
|
231
|
+
|
|
232
|
+
subject.fifo?
|
|
233
|
+
subject.fifo?
|
|
234
|
+
end
|
|
161
235
|
end
|
|
162
236
|
end
|
|
163
237
|
end
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
require 'shoryuken/runner'
|
|
3
|
-
require 'shoryuken/launcher'
|
|
4
3
|
|
|
5
4
|
# rubocop:disable Metrics/BlockLength
|
|
6
5
|
RSpec.describe Shoryuken::Runner do
|
|
@@ -17,10 +16,10 @@ RSpec.describe Shoryuken::Runner do
|
|
|
17
16
|
describe '#run' do
|
|
18
17
|
let(:launcher) { instance_double('Shoryuken::Launcher') }
|
|
19
18
|
|
|
20
|
-
before
|
|
19
|
+
before do
|
|
21
20
|
allow(Shoryuken::Launcher).to receive(:new).and_return(launcher)
|
|
22
|
-
allow(launcher).to receive(:
|
|
23
|
-
allow(launcher).to receive(:stop)
|
|
21
|
+
allow(launcher).to receive(:start).and_raise(Interrupt)
|
|
22
|
+
allow(launcher).to receive(:stop!)
|
|
24
23
|
end
|
|
25
24
|
|
|
26
25
|
it 'does not raise' do
|
data/spec/shoryuken/util_spec.rb
CHANGED
|
@@ -26,4 +26,28 @@ describe 'Shoryuken::Util' do
|
|
|
26
26
|
|
|
27
27
|
it 'returns ActiveJob worker name'
|
|
28
28
|
end
|
|
29
|
+
|
|
30
|
+
describe '#fire_event' do
|
|
31
|
+
let(:value_holder) { Object.new }
|
|
32
|
+
let(:callback_without_options) { proc { value_holder.value = :without_options } }
|
|
33
|
+
let(:callback_with_options) { proc { |options| value_holder.value = [:with_options, options] } }
|
|
34
|
+
|
|
35
|
+
after :all do
|
|
36
|
+
Shoryuken.options[:lifecycle_events].delete(:some_event)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it 'triggers callbacks that do not accept arguments' do
|
|
40
|
+
Shoryuken.options[:lifecycle_events][:some_event] = [callback_without_options]
|
|
41
|
+
|
|
42
|
+
expect(value_holder).to receive(:value=).with(:without_options)
|
|
43
|
+
subject.fire_event(:some_event)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it 'triggers callbacks that accept an argument' do
|
|
47
|
+
Shoryuken.options[:lifecycle_events][:some_event] = [callback_with_options]
|
|
48
|
+
|
|
49
|
+
expect(value_holder).to receive(:value=).with([:with_options, { my_option: :some_option }])
|
|
50
|
+
subject.fire_event(:some_event, false, my_option: :some_option)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
29
53
|
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
RSpec.describe Shoryuken::Worker::DefaultExecutor do
|
|
4
|
+
let(:sqs_queue) { double 'SQS Queue' }
|
|
5
|
+
let(:queue) { 'default' }
|
|
6
|
+
|
|
7
|
+
before do
|
|
8
|
+
allow(Shoryuken::Client).to receive(:queues).with(queue).and_return(sqs_queue)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe '.perform_in' do
|
|
12
|
+
it 'delays a message' do
|
|
13
|
+
expect(sqs_queue).to receive(:send_message).with(
|
|
14
|
+
message_attributes: {
|
|
15
|
+
'shoryuken_class' => {
|
|
16
|
+
string_value: TestWorker.to_s,
|
|
17
|
+
data_type: 'String'
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
message_body: 'message',
|
|
21
|
+
delay_seconds: 60
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
TestWorker.perform_in(60, 'message')
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it 'raises an exception' do
|
|
28
|
+
expect {
|
|
29
|
+
TestWorker.perform_in(901, 'message')
|
|
30
|
+
}.to raise_error 'The maximum allowed delay is 15 minutes'
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
describe '.perform_at' do
|
|
35
|
+
it 'delays a message' do
|
|
36
|
+
expect(sqs_queue).to receive(:send_message).with(
|
|
37
|
+
message_attributes: {
|
|
38
|
+
'shoryuken_class' => {
|
|
39
|
+
string_value: TestWorker.to_s,
|
|
40
|
+
data_type: 'String'
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
message_body: 'message',
|
|
44
|
+
delay_seconds: 60
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
TestWorker.perform_in(Time.now + 60, 'message')
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it 'raises an exception' do
|
|
51
|
+
expect {
|
|
52
|
+
TestWorker.perform_in(Time.now + 901, 'message')
|
|
53
|
+
}.to raise_error 'The maximum allowed delay is 15 minutes'
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
describe '.perform_async' do
|
|
58
|
+
it 'enqueues a message' do
|
|
59
|
+
expect(sqs_queue).to receive(:send_message).with(
|
|
60
|
+
message_attributes: {
|
|
61
|
+
'shoryuken_class' => {
|
|
62
|
+
string_value: TestWorker.to_s,
|
|
63
|
+
data_type: 'String'
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
message_body: 'message'
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
TestWorker.perform_async('message')
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it 'enqueues a message with options' do
|
|
73
|
+
expect(sqs_queue).to receive(:send_message).with(
|
|
74
|
+
delay_seconds: 60,
|
|
75
|
+
message_attributes: {
|
|
76
|
+
'shoryuken_class' => {
|
|
77
|
+
string_value: TestWorker.to_s,
|
|
78
|
+
data_type: 'String'
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
message_body: 'delayed message'
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
TestWorker.perform_async('delayed message', delay_seconds: 60)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it 'accepts an `queue` option' do
|
|
88
|
+
new_queue = 'some_different_queue'
|
|
89
|
+
|
|
90
|
+
expect(Shoryuken::Client).to receive(:queues).with(new_queue).and_return(sqs_queue)
|
|
91
|
+
|
|
92
|
+
expect(sqs_queue).to receive(:send_message).with(
|
|
93
|
+
message_attributes: {
|
|
94
|
+
'shoryuken_class' => {
|
|
95
|
+
string_value: TestWorker.to_s,
|
|
96
|
+
data_type: 'String'
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
message_body: 'delayed message'
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
TestWorker.perform_async('delayed message', queue: new_queue)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
RSpec.describe Shoryuken::Worker::InlineExecutor do
|
|
4
|
+
before do
|
|
5
|
+
Shoryuken.worker_executor = described_class
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
describe '.perform_async' do
|
|
9
|
+
specify do
|
|
10
|
+
expect_any_instance_of(TestWorker).to receive(:perform).with(anything, 'test')
|
|
11
|
+
|
|
12
|
+
TestWorker.perform_async('test')
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
describe '.perform_in' do
|
|
17
|
+
specify do
|
|
18
|
+
expect_any_instance_of(TestWorker).to receive(:perform).with(anything, 'test')
|
|
19
|
+
|
|
20
|
+
TestWorker.perform_in(60, 'test')
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
context 'batch' do
|
|
25
|
+
before do
|
|
26
|
+
TestWorker.get_shoryuken_options['batch'] = true
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
after do
|
|
30
|
+
TestWorker.get_shoryuken_options['batch'] = false
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
describe '.perform_async' do
|
|
34
|
+
specify do
|
|
35
|
+
expect_any_instance_of(TestWorker).to receive(:perform).with(anything, ['test'])
|
|
36
|
+
|
|
37
|
+
TestWorker.perform_async('test')
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
describe '.perform_in' do
|
|
42
|
+
specify do
|
|
43
|
+
expect_any_instance_of(TestWorker).to receive(:perform).with(anything, ['test'])
|
|
44
|
+
|
|
45
|
+
TestWorker.perform_in(60, 'test')
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
|
|
3
|
-
RSpec.describe
|
|
3
|
+
RSpec.describe Shoryuken::Worker do
|
|
4
4
|
let(:sqs_queue) { double 'SQS Queue' }
|
|
5
5
|
let(:queue) { 'default' }
|
|
6
6
|
|
|
@@ -8,96 +8,6 @@ RSpec.describe 'Shoryuken::Worker' do
|
|
|
8
8
|
allow(Shoryuken::Client).to receive(:queues).with(queue).and_return(sqs_queue)
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
describe '.perform_in' do
|
|
12
|
-
it 'delays a message' do
|
|
13
|
-
expect(sqs_queue).to receive(:send_message).with(
|
|
14
|
-
message_attributes: {
|
|
15
|
-
'shoryuken_class' => {
|
|
16
|
-
string_value: TestWorker.to_s,
|
|
17
|
-
data_type: 'String'
|
|
18
|
-
}
|
|
19
|
-
},
|
|
20
|
-
message_body: 'message',
|
|
21
|
-
delay_seconds: 60)
|
|
22
|
-
|
|
23
|
-
TestWorker.perform_in(60, 'message')
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
it 'raises an exception' do
|
|
27
|
-
expect {
|
|
28
|
-
TestWorker.perform_in(901, 'message')
|
|
29
|
-
}.to raise_error 'The maximum allowed delay is 15 minutes'
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
describe '.perform_at' do
|
|
34
|
-
it 'delays a message' do
|
|
35
|
-
expect(sqs_queue).to receive(:send_message).with(
|
|
36
|
-
message_attributes: {
|
|
37
|
-
'shoryuken_class' => {
|
|
38
|
-
string_value: TestWorker.to_s,
|
|
39
|
-
data_type: 'String'
|
|
40
|
-
}
|
|
41
|
-
},
|
|
42
|
-
message_body: 'message',
|
|
43
|
-
delay_seconds: 60)
|
|
44
|
-
|
|
45
|
-
TestWorker.perform_in(Time.now + 60, 'message')
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
it 'raises an exception' do
|
|
49
|
-
expect {
|
|
50
|
-
TestWorker.perform_in(Time.now + 901, 'message')
|
|
51
|
-
}.to raise_error 'The maximum allowed delay is 15 minutes'
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
describe '.perform_async' do
|
|
56
|
-
it 'enqueues a message' do
|
|
57
|
-
expect(sqs_queue).to receive(:send_message).with(
|
|
58
|
-
message_attributes: {
|
|
59
|
-
'shoryuken_class' => {
|
|
60
|
-
string_value: TestWorker.to_s,
|
|
61
|
-
data_type: 'String'
|
|
62
|
-
}
|
|
63
|
-
},
|
|
64
|
-
message_body: 'message')
|
|
65
|
-
|
|
66
|
-
TestWorker.perform_async('message')
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
it 'enqueues a message with options' do
|
|
70
|
-
expect(sqs_queue).to receive(:send_message).with(
|
|
71
|
-
delay_seconds: 60,
|
|
72
|
-
message_attributes: {
|
|
73
|
-
'shoryuken_class' => {
|
|
74
|
-
string_value: TestWorker.to_s,
|
|
75
|
-
data_type: 'String'
|
|
76
|
-
}
|
|
77
|
-
},
|
|
78
|
-
message_body: 'delayed message')
|
|
79
|
-
|
|
80
|
-
TestWorker.perform_async('delayed message', delay_seconds: 60)
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
it 'accepts an `queue` option' do
|
|
84
|
-
new_queue = 'some_different_queue'
|
|
85
|
-
|
|
86
|
-
expect(Shoryuken::Client).to receive(:queues).with(new_queue).and_return(sqs_queue)
|
|
87
|
-
|
|
88
|
-
expect(sqs_queue).to receive(:send_message).with(
|
|
89
|
-
message_attributes: {
|
|
90
|
-
'shoryuken_class' => {
|
|
91
|
-
string_value: TestWorker.to_s,
|
|
92
|
-
data_type: 'String'
|
|
93
|
-
}
|
|
94
|
-
},
|
|
95
|
-
message_body: 'delayed message')
|
|
96
|
-
|
|
97
|
-
TestWorker.perform_async('delayed message', queue: new_queue)
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
|
|
101
11
|
describe '.shoryuken_options' do
|
|
102
12
|
it 'registers a worker' do
|
|
103
13
|
expect(Shoryuken.worker_registry.workers('default')).to eq([TestWorker])
|
|
@@ -109,13 +19,27 @@ RSpec.describe 'Shoryuken::Worker' do
|
|
|
109
19
|
class NewTestWorker
|
|
110
20
|
include Shoryuken::Worker
|
|
111
21
|
|
|
112
|
-
shoryuken_options queue: ->{ "#{$queue_prefix}_default" }
|
|
22
|
+
shoryuken_options queue: -> { "#{$queue_prefix}_default" }
|
|
113
23
|
end
|
|
114
24
|
|
|
115
25
|
expect(Shoryuken.worker_registry.workers('production_default')).to eq([NewTestWorker])
|
|
116
26
|
expect(NewTestWorker.get_shoryuken_options['queue']).to eq 'production_default'
|
|
117
27
|
end
|
|
118
28
|
|
|
29
|
+
it 'does not change the original hash' do
|
|
30
|
+
class TestWorker
|
|
31
|
+
include Shoryuken::Worker
|
|
32
|
+
|
|
33
|
+
OPT = { queue: :default }.freeze
|
|
34
|
+
|
|
35
|
+
shoryuken_options OPT
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
expect(TestWorker::OPT['queue']).to eq(nil)
|
|
39
|
+
expect(TestWorker.get_shoryuken_options['queue']).to eq('default')
|
|
40
|
+
expect(TestWorker::OPT[:queue]).to eq(:default)
|
|
41
|
+
end
|
|
42
|
+
|
|
119
43
|
it 'accepts an array as a queue' do
|
|
120
44
|
class WorkerMultipleQueues
|
|
121
45
|
include Shoryuken::Worker
|
|
@@ -164,12 +88,29 @@ RSpec.describe 'Shoryuken::Worker' do
|
|
|
164
88
|
expect(Shoryuken.worker_registry.workers('symbol_queue2')).to eq([WorkerMultipleSymbolQueues])
|
|
165
89
|
expect(Shoryuken.worker_registry.workers('symbol_queue3')).to eq([WorkerMultipleSymbolQueues])
|
|
166
90
|
end
|
|
91
|
+
|
|
92
|
+
it 'preserves parent class options' do
|
|
93
|
+
class ParentWorker
|
|
94
|
+
include Shoryuken::Worker
|
|
95
|
+
|
|
96
|
+
shoryuken_options queue: 'myqueue', auto_delete: false
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
class ChildWorker < ParentWorker
|
|
100
|
+
shoryuken_options auto_delete: true
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
expect(ParentWorker.get_shoryuken_options['queue']).to eq('myqueue')
|
|
104
|
+
expect(ChildWorker.get_shoryuken_options['queue']).to eq('myqueue')
|
|
105
|
+
expect(ParentWorker.get_shoryuken_options['auto_delete']).to eq(false)
|
|
106
|
+
expect(ChildWorker.get_shoryuken_options['auto_delete']).to eq(true)
|
|
107
|
+
end
|
|
167
108
|
end
|
|
168
109
|
|
|
169
110
|
describe '.server_middleware' do
|
|
170
111
|
before do
|
|
171
112
|
class FakeMiddleware
|
|
172
|
-
def call(*
|
|
113
|
+
def call(*_args)
|
|
173
114
|
yield
|
|
174
115
|
end
|
|
175
116
|
end
|
|
@@ -192,9 +133,7 @@ RSpec.describe 'Shoryuken::Worker' do
|
|
|
192
133
|
class NewTestWorker2
|
|
193
134
|
include Shoryuken::Worker
|
|
194
135
|
|
|
195
|
-
server_middleware
|
|
196
|
-
chain.clear
|
|
197
|
-
end
|
|
136
|
+
server_middleware(&:clear)
|
|
198
137
|
end
|
|
199
138
|
end
|
|
200
139
|
|
data/spec/shoryuken_spec.rb
CHANGED
|
@@ -1,63 +1,4 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
|
|
3
3
|
RSpec.describe Shoryuken do
|
|
4
|
-
describe '.add_queue' do
|
|
5
|
-
after { Shoryuken.queues.clear }
|
|
6
|
-
|
|
7
|
-
it 'adds queues' do
|
|
8
|
-
described_class.add_queue('default')
|
|
9
|
-
expect(described_class.queues).to eq(['default'])
|
|
10
|
-
|
|
11
|
-
described_class.add_queue('high', 2)
|
|
12
|
-
expect(described_class.queues).to eq(%w(default high high))
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
describe '.register_worker' do
|
|
17
|
-
it 'registers a worker' do
|
|
18
|
-
described_class.worker_registry.clear
|
|
19
|
-
described_class.register_worker('default', TestWorker)
|
|
20
|
-
expect(described_class.worker_registry.workers('default')).to eq([TestWorker])
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
it 'registers a batchable worker' do
|
|
24
|
-
described_class.worker_registry.clear
|
|
25
|
-
TestWorker.get_shoryuken_options['batch'] = true
|
|
26
|
-
described_class.register_worker('default', TestWorker)
|
|
27
|
-
expect(described_class.worker_registry.workers('default')).to eq([TestWorker])
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
it 'allows multiple workers' do
|
|
31
|
-
described_class.worker_registry.clear
|
|
32
|
-
described_class.register_worker('default', TestWorker)
|
|
33
|
-
expect(described_class.worker_registry.workers('default')).to eq([TestWorker])
|
|
34
|
-
|
|
35
|
-
class Test2Worker
|
|
36
|
-
include Shoryuken::Worker
|
|
37
|
-
|
|
38
|
-
shoryuken_options queue: 'default'
|
|
39
|
-
|
|
40
|
-
def perform(sqs_msg, body); end
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
expect(described_class.worker_registry.workers('default')).to eq([Test2Worker])
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
it 'raises an exception when mixing batchable with non batchable' do
|
|
47
|
-
described_class.worker_registry.clear
|
|
48
|
-
TestWorker.get_shoryuken_options['batch'] = true
|
|
49
|
-
described_class.register_worker('default', TestWorker)
|
|
50
|
-
|
|
51
|
-
expect {
|
|
52
|
-
class BatchableWorker
|
|
53
|
-
include Shoryuken::Worker
|
|
54
|
-
|
|
55
|
-
shoryuken_options queue: 'default', batch: true
|
|
56
|
-
|
|
57
|
-
def perform(sqs_msg, body); end
|
|
58
|
-
end
|
|
59
|
-
}.to raise_error("Could not register BatchableWorker for 'default', because TestWorker is already registered for this queue, " \
|
|
60
|
-
"and Shoryuken doesn't support a batchable worker for a queue with multiple workers")
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
4
|
end
|