shoryuken 3.1.3 → 3.2.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 +1 -1
- data/.travis.yml +13 -3
- data/CHANGELOG.md +68 -0
- data/Gemfile +5 -3
- data/Gemfile.aws-sdk-core-v2 +13 -0
- data/bin/cli/sqs.rb +8 -4
- data/bin/shoryuken +2 -1
- data/lib/shoryuken/body_parser.rb +27 -0
- data/lib/shoryuken/fetcher.rb +40 -13
- data/lib/shoryuken/launcher.rb +2 -17
- data/lib/shoryuken/manager.rb +17 -5
- data/lib/shoryuken/middleware/chain.rb +4 -0
- data/lib/shoryuken/middleware/server/auto_extend_visibility.rb +2 -5
- data/lib/shoryuken/middleware/server/timing.rb +12 -14
- data/lib/shoryuken/options.rb +21 -1
- data/lib/shoryuken/processor.rb +5 -21
- data/lib/shoryuken/queue.rb +12 -5
- data/lib/shoryuken/runner.rb +3 -1
- data/lib/shoryuken/util.rb +2 -2
- data/lib/shoryuken/version.rb +1 -1
- data/lib/shoryuken/worker/default_executor.rb +33 -0
- data/lib/shoryuken/worker/inline_executor.rb +28 -0
- data/lib/shoryuken/worker.rb +68 -31
- data/lib/shoryuken.rb +12 -0
- data/shoryuken.gemspec +1 -1
- data/spec/shoryuken/body_parser_spec.rb +89 -0
- data/spec/shoryuken/fetcher_spec.rb +61 -9
- data/spec/shoryuken/manager_spec.rb +2 -2
- data/spec/shoryuken/middleware/chain_spec.rb +16 -4
- data/spec/shoryuken/options_spec.rb +80 -0
- data/spec/shoryuken/processor_spec.rb +15 -97
- data/spec/shoryuken/queue_spec.rb +43 -32
- data/spec/shoryuken/util_spec.rb +25 -1
- data/spec/shoryuken/worker/default_executor_spec.rb +100 -0
- data/spec/shoryuken/worker/inline_executor_spec.rb +23 -0
- data/spec/shoryuken/worker_spec.rb +32 -91
- data/spec/spec_helper.rb +2 -0
- metadata +15 -5
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Shoryuken
|
|
2
|
+
module Worker
|
|
3
|
+
class InlineExecutor
|
|
4
|
+
class << self
|
|
5
|
+
def perform_async(worker_class, body, options = {})
|
|
6
|
+
body = JSON.dump(body) if body.is_a?(Hash)
|
|
7
|
+
|
|
8
|
+
sqs_msg = OpenStruct.new(
|
|
9
|
+
body: body,
|
|
10
|
+
attributes: nil,
|
|
11
|
+
md5_of_body: nil,
|
|
12
|
+
md5_of_message_attributes: nil,
|
|
13
|
+
message_attributes: nil,
|
|
14
|
+
message_id: nil,
|
|
15
|
+
receipt_handle: nil,
|
|
16
|
+
delete: nil
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
worker_class.new.perform(sqs_msg, BodyParser.parse(worker_class, sqs_msg))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def perform_in(worker_class, _interval, body, options = {})
|
|
23
|
+
perform_async(worker_class, body, options)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
data/lib/shoryuken/worker.rb
CHANGED
|
@@ -2,33 +2,16 @@ module Shoryuken
|
|
|
2
2
|
module Worker
|
|
3
3
|
def self.included(base)
|
|
4
4
|
base.extend(ClassMethods)
|
|
5
|
+
base.shoryuken_class_attribute :shoryuken_options_hash
|
|
5
6
|
end
|
|
6
7
|
|
|
7
8
|
module ClassMethods
|
|
8
9
|
def perform_async(body, options = {})
|
|
9
|
-
|
|
10
|
-
options[:message_attributes]['shoryuken_class'] = {
|
|
11
|
-
string_value: self.to_s,
|
|
12
|
-
data_type: 'String'
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
options[:message_body] = body
|
|
16
|
-
|
|
17
|
-
queue = options.delete(:queue) || get_shoryuken_options['queue']
|
|
18
|
-
|
|
19
|
-
Shoryuken::Client.queues(queue).send_message(options)
|
|
10
|
+
Shoryuken.worker_executor.perform_async(self, body, options)
|
|
20
11
|
end
|
|
21
12
|
|
|
22
13
|
def perform_in(interval, body, options = {})
|
|
23
|
-
interval
|
|
24
|
-
now = Time.now.to_f
|
|
25
|
-
ts = (interval < 1_000_000_000 ? (now + interval).to_f : interval)
|
|
26
|
-
|
|
27
|
-
delay = (ts - now).ceil
|
|
28
|
-
|
|
29
|
-
raise 'The maximum allowed delay is 15 minutes' if delay > 15 * 60
|
|
30
|
-
|
|
31
|
-
perform_async(body, options.merge(delay_seconds: delay))
|
|
14
|
+
Shoryuken.worker_executor.perform_in(self, interval, body, options)
|
|
32
15
|
end
|
|
33
16
|
|
|
34
17
|
alias_method :perform_at, :perform_in
|
|
@@ -40,7 +23,7 @@ module Shoryuken
|
|
|
40
23
|
end
|
|
41
24
|
|
|
42
25
|
def shoryuken_options(opts = {})
|
|
43
|
-
|
|
26
|
+
self.shoryuken_options_hash = get_shoryuken_options.merge(stringify_keys(opts || {}))
|
|
44
27
|
normalize_worker_queue!
|
|
45
28
|
end
|
|
46
29
|
|
|
@@ -57,33 +40,87 @@ module Shoryuken
|
|
|
57
40
|
end
|
|
58
41
|
|
|
59
42
|
def get_shoryuken_options # :nodoc:
|
|
60
|
-
|
|
43
|
+
shoryuken_options_hash || Shoryuken.default_worker_options
|
|
61
44
|
end
|
|
62
45
|
|
|
63
46
|
def stringify_keys(hash) # :nodoc:
|
|
64
|
-
|
|
65
|
-
|
|
47
|
+
new_hash = {}
|
|
48
|
+
hash.each { |key, value| new_hash[key.to_s] = value }
|
|
49
|
+
new_hash
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def shoryuken_class_attribute(*attrs) # :nodoc:
|
|
53
|
+
attrs.each do |name|
|
|
54
|
+
singleton_class.instance_eval do
|
|
55
|
+
undef_method(name) if method_defined?(name) || private_method_defined?(name)
|
|
56
|
+
end
|
|
57
|
+
define_singleton_method(name) { nil }
|
|
58
|
+
|
|
59
|
+
ivar = "@#{name}"
|
|
60
|
+
|
|
61
|
+
singleton_class.instance_eval do
|
|
62
|
+
m = "#{name}="
|
|
63
|
+
undef_method(m) if method_defined?(m) || private_method_defined?(m)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
define_singleton_method("#{name}=") do |val|
|
|
67
|
+
singleton_class.class_eval do
|
|
68
|
+
undef_method(name) if method_defined?(name) || private_method_defined?(name)
|
|
69
|
+
define_method(name) { val }
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# singleton? backwards compatibility for ruby < 2.1
|
|
73
|
+
singleton_klass = respond_to?(:singleton?) ? singleton? : self != ancestors.first
|
|
74
|
+
|
|
75
|
+
if singleton_klass
|
|
76
|
+
class_eval do
|
|
77
|
+
undef_method(name) if method_defined?(name) || private_method_defined?(name)
|
|
78
|
+
define_method(name) do
|
|
79
|
+
if instance_variable_defined? ivar
|
|
80
|
+
instance_variable_get ivar
|
|
81
|
+
else
|
|
82
|
+
singleton_class.send name
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
val
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# instance reader
|
|
91
|
+
undef_method(name) if method_defined?(name) || private_method_defined?(name)
|
|
92
|
+
define_method(name) do
|
|
93
|
+
if instance_variable_defined?(ivar)
|
|
94
|
+
instance_variable_get ivar
|
|
95
|
+
else
|
|
96
|
+
self.class.public_send name
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# instance writer
|
|
101
|
+
m = "#{name}="
|
|
102
|
+
undef_method(m) if method_defined?(m) || private_method_defined?(m)
|
|
103
|
+
attr_writer name
|
|
66
104
|
end
|
|
67
|
-
hash
|
|
68
105
|
end
|
|
69
106
|
|
|
70
107
|
private
|
|
71
108
|
|
|
72
109
|
def normalize_worker_queue!
|
|
73
|
-
queue =
|
|
110
|
+
queue = shoryuken_options_hash['queue']
|
|
74
111
|
if queue.respond_to?(:call)
|
|
75
112
|
queue = queue.call
|
|
76
|
-
|
|
113
|
+
shoryuken_options_hash['queue'] = queue
|
|
77
114
|
end
|
|
78
115
|
|
|
79
|
-
case
|
|
116
|
+
case shoryuken_options_hash['queue']
|
|
80
117
|
when Array
|
|
81
|
-
|
|
118
|
+
shoryuken_options_hash['queue'].map!(&:to_s)
|
|
82
119
|
when Symbol
|
|
83
|
-
|
|
120
|
+
shoryuken_options_hash['queue'] = shoryuken_options_hash['queue'].to_s
|
|
84
121
|
end
|
|
85
122
|
|
|
86
|
-
[
|
|
123
|
+
[shoryuken_options_hash['queue']].flatten.compact.each(&method(:register_worker))
|
|
87
124
|
end
|
|
88
125
|
|
|
89
126
|
def register_worker(queue)
|
data/lib/shoryuken.rb
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
require 'yaml'
|
|
2
2
|
require 'json'
|
|
3
3
|
require 'aws-sdk-core'
|
|
4
|
+
begin
|
|
5
|
+
require 'aws-sdk-sqs' unless defined?(Aws::SQS)
|
|
6
|
+
rescue LoadError
|
|
7
|
+
fail "AWS SDK 3 requires aws-sdk-sqs to be installed separately. Please add gem 'aws-sdk-sqs' to your Gemfile"
|
|
8
|
+
end
|
|
4
9
|
require 'time'
|
|
5
10
|
require 'concurrent'
|
|
11
|
+
require 'forwardable'
|
|
6
12
|
|
|
7
13
|
require 'shoryuken/version'
|
|
8
14
|
require 'shoryuken/core_ext'
|
|
@@ -13,6 +19,8 @@ require 'shoryuken/queue'
|
|
|
13
19
|
require 'shoryuken/message'
|
|
14
20
|
require 'shoryuken/client'
|
|
15
21
|
require 'shoryuken/worker'
|
|
22
|
+
require 'shoryuken/worker/default_executor'
|
|
23
|
+
require 'shoryuken/worker/inline_executor'
|
|
16
24
|
require 'shoryuken/worker_registry'
|
|
17
25
|
require 'shoryuken/default_worker_registry'
|
|
18
26
|
require 'shoryuken/middleware/chain'
|
|
@@ -26,9 +34,11 @@ require 'shoryuken/polling/strict_priority'
|
|
|
26
34
|
require 'shoryuken/manager'
|
|
27
35
|
require 'shoryuken/launcher'
|
|
28
36
|
require 'shoryuken/processor'
|
|
37
|
+
require 'shoryuken/body_parser'
|
|
29
38
|
require 'shoryuken/fetcher'
|
|
30
39
|
require 'shoryuken/options'
|
|
31
40
|
|
|
41
|
+
|
|
32
42
|
module Shoryuken
|
|
33
43
|
extend SingleForwardable
|
|
34
44
|
|
|
@@ -41,6 +51,8 @@ module Shoryuken
|
|
|
41
51
|
:ungrouped_queues,
|
|
42
52
|
:worker_registry,
|
|
43
53
|
:worker_registry=,
|
|
54
|
+
:worker_executor,
|
|
55
|
+
:worker_executor=,
|
|
44
56
|
:polling_strategy,
|
|
45
57
|
:start_callback,
|
|
46
58
|
:start_callback=,
|
data/shoryuken.gemspec
CHANGED
|
@@ -23,7 +23,7 @@ Gem::Specification.new do |spec|
|
|
|
23
23
|
spec.add_development_dependency 'pry-byebug'
|
|
24
24
|
spec.add_development_dependency 'dotenv'
|
|
25
25
|
|
|
26
|
-
spec.add_dependency 'aws-sdk-core', '
|
|
26
|
+
spec.add_dependency 'aws-sdk-core', '>= 2'
|
|
27
27
|
spec.add_dependency 'concurrent-ruby'
|
|
28
28
|
spec.add_dependency 'thor'
|
|
29
29
|
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'shoryuken/body_parser'
|
|
3
|
+
|
|
4
|
+
RSpec.describe Shoryuken::BodyParser do
|
|
5
|
+
let(:sqs_msg) { double }
|
|
6
|
+
|
|
7
|
+
describe '#parser' do
|
|
8
|
+
it 'parses the body into JSON' do
|
|
9
|
+
TestWorker.get_shoryuken_options['body_parser'] = :json
|
|
10
|
+
|
|
11
|
+
body = { 'test' => 'hi' }
|
|
12
|
+
|
|
13
|
+
allow(sqs_msg).to receive(:body).and_return(JSON.dump(body))
|
|
14
|
+
|
|
15
|
+
expect(described_class.parse(TestWorker, sqs_msg)).to eq(body)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'parses the body calling the proc' do
|
|
19
|
+
TestWorker.get_shoryuken_options['body_parser'] = proc { |sqs_msg| "*#{sqs_msg.body}*" }
|
|
20
|
+
|
|
21
|
+
allow(sqs_msg).to receive(:body).and_return('test')
|
|
22
|
+
|
|
23
|
+
expect(described_class.parse(TestWorker, sqs_msg)).to eq('*test*')
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'parses the body as text' do
|
|
27
|
+
TestWorker.get_shoryuken_options['body_parser'] = :text
|
|
28
|
+
|
|
29
|
+
body = 'test'
|
|
30
|
+
|
|
31
|
+
allow(sqs_msg).to receive(:body).and_return(body)
|
|
32
|
+
|
|
33
|
+
expect(described_class.parse(TestWorker, sqs_msg)).to eq('test')
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it 'parses calling `.load`' do
|
|
37
|
+
TestWorker.get_shoryuken_options['body_parser'] = Class.new do
|
|
38
|
+
def self.load(*args)
|
|
39
|
+
JSON.load(*args)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
body = { 'test' => 'hi' }
|
|
44
|
+
|
|
45
|
+
allow(sqs_msg).to receive(:body).and_return(JSON.dump(body))
|
|
46
|
+
|
|
47
|
+
expect(described_class.parse(TestWorker, sqs_msg)).to eq(body)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it 'parses calling `.parse`' do
|
|
51
|
+
TestWorker.get_shoryuken_options['body_parser'] = Class.new do
|
|
52
|
+
def self.parse(*args)
|
|
53
|
+
JSON.parse(*args)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
body = { 'test' => 'hi' }
|
|
58
|
+
|
|
59
|
+
allow(sqs_msg).to receive(:body).and_return(JSON.dump(body))
|
|
60
|
+
|
|
61
|
+
expect(described_class.parse(TestWorker, sqs_msg)).to eq(body)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
context 'when parse errors' do
|
|
65
|
+
before do
|
|
66
|
+
TestWorker.get_shoryuken_options['body_parser'] = :json
|
|
67
|
+
|
|
68
|
+
allow(sqs_msg).to receive(:body).and_return('invalid JSON')
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
specify do
|
|
72
|
+
expect { described_class.parse(TestWorker, sqs_msg) }.
|
|
73
|
+
to raise_error(JSON::ParserError, /unexpected token at 'invalid JSON'/)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
context 'when `object_type: nil`' do
|
|
78
|
+
it 'parses the body as text' do
|
|
79
|
+
TestWorker.get_shoryuken_options['body_parser'] = nil
|
|
80
|
+
|
|
81
|
+
body = 'test'
|
|
82
|
+
|
|
83
|
+
allow(sqs_msg).to receive(:body).and_return(body)
|
|
84
|
+
|
|
85
|
+
expect(described_class.parse(TestWorker, sqs_msg)).to eq(body)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -2,6 +2,7 @@ require 'spec_helper'
|
|
|
2
2
|
require 'shoryuken/manager'
|
|
3
3
|
require 'shoryuken/fetcher'
|
|
4
4
|
|
|
5
|
+
# rubocop:disable Metrics/BlockLength
|
|
5
6
|
RSpec.describe Shoryuken::Fetcher do
|
|
6
7
|
let(:queue) { instance_double('Shoryuken::Queue') }
|
|
7
8
|
let(:queue_name) { 'default' }
|
|
@@ -13,7 +14,7 @@ RSpec.describe Shoryuken::Fetcher do
|
|
|
13
14
|
Shoryuken::Message,
|
|
14
15
|
queue_url: queue_name,
|
|
15
16
|
body: 'test',
|
|
16
|
-
message_id: 'fc754df79cc24c4196ca5996a44b771e'
|
|
17
|
+
message_id: 'fc754df79cc24c4196ca5996a44b771e'
|
|
17
18
|
)
|
|
18
19
|
end
|
|
19
20
|
|
|
@@ -27,23 +28,74 @@ RSpec.describe Shoryuken::Fetcher do
|
|
|
27
28
|
|
|
28
29
|
Shoryuken.sqs_client_receive_message_opts[group] = { wait_time_seconds: 10 }
|
|
29
30
|
|
|
30
|
-
expect(queue).to receive(:receive_messages).
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
expect(queue).to receive(:receive_messages).with(
|
|
32
|
+
wait_time_seconds: 10,
|
|
33
|
+
max_number_of_messages: limit,
|
|
34
|
+
message_attribute_names: ['All'],
|
|
35
|
+
attribute_names: ['All']
|
|
36
|
+
).and_return([])
|
|
33
37
|
|
|
34
38
|
subject.fetch(queue_config, limit)
|
|
35
39
|
end
|
|
36
40
|
|
|
41
|
+
it 'logs debug only' do
|
|
42
|
+
# See https://github.com/phstc/shoryuken/issues/435
|
|
43
|
+
logger = double 'logger'
|
|
44
|
+
|
|
45
|
+
allow(subject).to receive(:logger).and_return(logger)
|
|
46
|
+
|
|
47
|
+
expect(Shoryuken::Client).to receive(:queues).with(queue_name).and_return(queue)
|
|
48
|
+
|
|
49
|
+
expect(queue).to receive(:receive_messages).and_return([double('SQS Msg')])
|
|
50
|
+
|
|
51
|
+
expect(logger).to receive(:debug).exactly(3).times
|
|
52
|
+
expect(logger).to_not receive(:info)
|
|
53
|
+
|
|
54
|
+
subject.fetch(queue_config, limit)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
context 'when receive options per queue' do
|
|
58
|
+
let(:limit) { 5 }
|
|
59
|
+
|
|
60
|
+
specify do
|
|
61
|
+
expect(Shoryuken::Client).to receive(:queues).with(queue_name).and_return(queue)
|
|
62
|
+
|
|
63
|
+
Shoryuken.sqs_client_receive_message_opts[queue_name] = { max_number_of_messages: 1 }
|
|
64
|
+
|
|
65
|
+
expect(queue).to receive(:receive_messages).with(
|
|
66
|
+
max_number_of_messages: 1,
|
|
67
|
+
message_attribute_names: ['All'],
|
|
68
|
+
attribute_names: ['All']
|
|
69
|
+
).and_return([])
|
|
70
|
+
|
|
71
|
+
subject.fetch(queue_config, limit)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
context 'when max_number_of_messages opt is great than limit' do
|
|
76
|
+
it 'uses limit' do
|
|
77
|
+
expect(Shoryuken::Client).to receive(:queues).with(queue_name).and_return(queue)
|
|
78
|
+
|
|
79
|
+
Shoryuken.sqs_client_receive_message_opts[queue_name] = { max_number_of_messages: 20 }
|
|
80
|
+
|
|
81
|
+
expect(queue).to receive(:receive_messages).with(
|
|
82
|
+
max_number_of_messages: limit,
|
|
83
|
+
message_attribute_names: ['All'],
|
|
84
|
+
attribute_names: ['All']
|
|
85
|
+
).and_return([])
|
|
86
|
+
|
|
87
|
+
subject.fetch(queue_config, limit)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
37
91
|
context 'when limit is greater than FETCH_LIMIT' do
|
|
38
92
|
let(:limit) { 20 }
|
|
39
93
|
|
|
40
94
|
specify do
|
|
41
|
-
Shoryuken.sqs_client_receive_message_opts[group] = {}
|
|
42
|
-
|
|
43
95
|
allow(Shoryuken::Client).to receive(:queues).with(queue_name).and_return(queue)
|
|
44
|
-
expect(queue).to receive(:receive_messages).
|
|
45
|
-
|
|
46
|
-
|
|
96
|
+
expect(queue).to receive(:receive_messages).with(
|
|
97
|
+
max_number_of_messages: described_class::FETCH_LIMIT, attribute_names: ['All'], message_attribute_names: ['All']
|
|
98
|
+
).and_return([])
|
|
47
99
|
|
|
48
100
|
subject.fetch(queue_config, limit)
|
|
49
101
|
end
|
|
@@ -70,7 +70,7 @@ RSpec.describe Shoryuken::Manager do
|
|
|
70
70
|
q = Shoryuken::Polling::QueueConfiguration.new(queue, {})
|
|
71
71
|
|
|
72
72
|
expect(fetcher).to receive(:fetch).with(q, concurrency).and_return(messages)
|
|
73
|
-
expect(subject).to receive(:fire_event).with(:dispatch)
|
|
73
|
+
expect(subject).to receive(:fire_event).with(:dispatch, false, queue_name: q.name)
|
|
74
74
|
expect(Shoryuken::Processor).to receive(:process).with(q, message)
|
|
75
75
|
expect(Shoryuken.logger).to_not receive(:info)
|
|
76
76
|
|
|
@@ -83,7 +83,7 @@ RSpec.describe Shoryuken::Manager do
|
|
|
83
83
|
q = Shoryuken::Polling::QueueConfiguration.new(queue, {})
|
|
84
84
|
|
|
85
85
|
expect(fetcher).to receive(:fetch).with(q, described_class::BATCH_LIMIT).and_return(messages)
|
|
86
|
-
expect(subject).to receive(:fire_event).with(:dispatch)
|
|
86
|
+
expect(subject).to receive(:fire_event).with(:dispatch, false, queue_name: q.name)
|
|
87
87
|
allow(subject).to receive(:batched_queue?).with(q).and_return(true)
|
|
88
88
|
expect(Shoryuken::Processor).to receive(:process).with(q, messages)
|
|
89
89
|
expect(Shoryuken.logger).to_not receive(:info)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
|
|
3
|
-
describe Shoryuken::Middleware::Chain do
|
|
3
|
+
RSpec.describe Shoryuken::Middleware::Chain do
|
|
4
4
|
class CustomMiddleware
|
|
5
5
|
def initialize(name, recorder)
|
|
6
6
|
@name = name
|
|
@@ -14,20 +14,32 @@ describe Shoryuken::Middleware::Chain do
|
|
|
14
14
|
end
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
+
class CustomMiddlewareB < CustomMiddleware; end
|
|
18
|
+
|
|
17
19
|
it 'supports custom middleware' do
|
|
18
20
|
subject.add CustomMiddleware, 1, []
|
|
19
21
|
|
|
20
22
|
expect(CustomMiddleware).to eq subject.entries.last.klass
|
|
21
23
|
end
|
|
22
24
|
|
|
25
|
+
it 'can add middleware to the front of chain' do
|
|
26
|
+
subject.prepend CustomMiddleware, 1, []
|
|
27
|
+
|
|
28
|
+
expect([CustomMiddleware]).to eq subject.entries.map(&:klass)
|
|
29
|
+
|
|
30
|
+
subject.prepend CustomMiddlewareB, 1, []
|
|
31
|
+
|
|
32
|
+
expect([CustomMiddlewareB, CustomMiddleware]).to eq subject.entries.map(&:klass)
|
|
33
|
+
end
|
|
34
|
+
|
|
23
35
|
it 'invokes a middleware' do
|
|
24
36
|
recorder = []
|
|
25
|
-
subject.add CustomMiddleware, '
|
|
37
|
+
subject.add CustomMiddleware, 'custom', recorder
|
|
26
38
|
|
|
27
39
|
final_action = nil
|
|
28
40
|
subject.invoke { final_action = true }
|
|
29
41
|
expect(final_action).to eq true
|
|
30
|
-
expect(recorder).to eq [%w
|
|
42
|
+
expect(recorder).to eq [%w(custom before), %w(custom after)]
|
|
31
43
|
end
|
|
32
44
|
|
|
33
45
|
class NonYieldingMiddleware
|
|
@@ -37,7 +49,7 @@ describe Shoryuken::Middleware::Chain do
|
|
|
37
49
|
it 'allows middleware to abruptly stop processing rest of chain' do
|
|
38
50
|
recorder = []
|
|
39
51
|
subject.add NonYieldingMiddleware
|
|
40
|
-
subject.add CustomMiddleware, '
|
|
52
|
+
subject.add CustomMiddleware, 'custom', recorder
|
|
41
53
|
|
|
42
54
|
final_action = nil
|
|
43
55
|
subject.invoke { final_action = true }
|
|
@@ -97,4 +97,84 @@ RSpec.describe Shoryuken::Options do
|
|
|
97
97
|
"and Shoryuken doesn't support a batchable worker for a queue with multiple workers")
|
|
98
98
|
end
|
|
99
99
|
end
|
|
100
|
+
|
|
101
|
+
describe '.polling_strategy' do
|
|
102
|
+
context 'when not set' do
|
|
103
|
+
specify do
|
|
104
|
+
expect(Shoryuken.polling_strategy('default')).to eq Shoryuken::Polling::WeightedRoundRobin
|
|
105
|
+
expect(Shoryuken.polling_strategy('group1')).to eq Shoryuken::Polling::WeightedRoundRobin
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
context 'when set to StrictPriority string' do
|
|
110
|
+
before do
|
|
111
|
+
Shoryuken.options[:polling_strategy] = 'StrictPriority'
|
|
112
|
+
|
|
113
|
+
Shoryuken.options[:groups] = {
|
|
114
|
+
'group1' => {
|
|
115
|
+
polling_strategy: 'StrictPriority'
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
specify do
|
|
121
|
+
expect(Shoryuken.polling_strategy('default')).to eq Shoryuken::Polling::StrictPriority
|
|
122
|
+
expect(Shoryuken.polling_strategy('group1')).to eq Shoryuken::Polling::StrictPriority
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
context 'when set to WeightedRoundRobin string' do
|
|
127
|
+
before do
|
|
128
|
+
Shoryuken.options[:polling_strategy] = 'WeightedRoundRobin'
|
|
129
|
+
|
|
130
|
+
Shoryuken.options[:groups] = {
|
|
131
|
+
'group1' => {
|
|
132
|
+
polling_strategy: 'WeightedRoundRobin'
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
specify do
|
|
138
|
+
expect(Shoryuken.polling_strategy('default')).to eq Shoryuken::Polling::WeightedRoundRobin
|
|
139
|
+
expect(Shoryuken.polling_strategy('group1')).to eq Shoryuken::Polling::WeightedRoundRobin
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
context 'when set to non-existent string' do
|
|
144
|
+
before do
|
|
145
|
+
Shoryuken.options[:polling_strategy] = 'NonExistent1'
|
|
146
|
+
|
|
147
|
+
Shoryuken.options[:groups] = {
|
|
148
|
+
'group1' => {
|
|
149
|
+
polling_strategy: 'NonExistent2'
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
specify do
|
|
155
|
+
expect { Shoryuken.polling_strategy('default') }.to raise_error(ArgumentError)
|
|
156
|
+
expect { Shoryuken.polling_strategy('group1') }.to raise_error(ArgumentError)
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
context 'when set to a class' do
|
|
161
|
+
before do
|
|
162
|
+
class Foo < Shoryuken::Polling::BaseStrategy; end
|
|
163
|
+
class Bar < Shoryuken::Polling::BaseStrategy; end
|
|
164
|
+
|
|
165
|
+
Shoryuken.options[:polling_strategy] = Foo
|
|
166
|
+
|
|
167
|
+
Shoryuken.options[:groups] = {
|
|
168
|
+
'group1' => {
|
|
169
|
+
polling_strategy: Bar
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
specify do
|
|
175
|
+
expect(Shoryuken.polling_strategy('default')).to eq Foo
|
|
176
|
+
expect(Shoryuken.polling_strategy('group1')).to eq Bar
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
100
180
|
end
|