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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/.travis.yml +13 -3
  4. data/CHANGELOG.md +68 -0
  5. data/Gemfile +5 -3
  6. data/Gemfile.aws-sdk-core-v2 +13 -0
  7. data/bin/cli/sqs.rb +8 -4
  8. data/bin/shoryuken +2 -1
  9. data/lib/shoryuken/body_parser.rb +27 -0
  10. data/lib/shoryuken/fetcher.rb +40 -13
  11. data/lib/shoryuken/launcher.rb +2 -17
  12. data/lib/shoryuken/manager.rb +17 -5
  13. data/lib/shoryuken/middleware/chain.rb +4 -0
  14. data/lib/shoryuken/middleware/server/auto_extend_visibility.rb +2 -5
  15. data/lib/shoryuken/middleware/server/timing.rb +12 -14
  16. data/lib/shoryuken/options.rb +21 -1
  17. data/lib/shoryuken/processor.rb +5 -21
  18. data/lib/shoryuken/queue.rb +12 -5
  19. data/lib/shoryuken/runner.rb +3 -1
  20. data/lib/shoryuken/util.rb +2 -2
  21. data/lib/shoryuken/version.rb +1 -1
  22. data/lib/shoryuken/worker/default_executor.rb +33 -0
  23. data/lib/shoryuken/worker/inline_executor.rb +28 -0
  24. data/lib/shoryuken/worker.rb +68 -31
  25. data/lib/shoryuken.rb +12 -0
  26. data/shoryuken.gemspec +1 -1
  27. data/spec/shoryuken/body_parser_spec.rb +89 -0
  28. data/spec/shoryuken/fetcher_spec.rb +61 -9
  29. data/spec/shoryuken/manager_spec.rb +2 -2
  30. data/spec/shoryuken/middleware/chain_spec.rb +16 -4
  31. data/spec/shoryuken/options_spec.rb +80 -0
  32. data/spec/shoryuken/processor_spec.rb +15 -97
  33. data/spec/shoryuken/queue_spec.rb +43 -32
  34. data/spec/shoryuken/util_spec.rb +25 -1
  35. data/spec/shoryuken/worker/default_executor_spec.rb +100 -0
  36. data/spec/shoryuken/worker/inline_executor_spec.rb +23 -0
  37. data/spec/shoryuken/worker_spec.rb +32 -91
  38. data/spec/spec_helper.rb +2 -0
  39. 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
@@ -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
- options[:message_attributes] ||= {}
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 = interval.to_f
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
- @shoryuken_options = get_shoryuken_options.merge(stringify_keys(opts || {}))
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
- @shoryuken_options || Shoryuken.default_worker_options
43
+ shoryuken_options_hash || Shoryuken.default_worker_options
61
44
  end
62
45
 
63
46
  def stringify_keys(hash) # :nodoc:
64
- hash.keys.each do |key|
65
- hash[key.to_s] = hash.delete(key)
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 = @shoryuken_options['queue']
110
+ queue = shoryuken_options_hash['queue']
74
111
  if queue.respond_to?(:call)
75
112
  queue = queue.call
76
- @shoryuken_options['queue'] = queue
113
+ shoryuken_options_hash['queue'] = queue
77
114
  end
78
115
 
79
- case @shoryuken_options['queue']
116
+ case shoryuken_options_hash['queue']
80
117
  when Array
81
- @shoryuken_options['queue'].map!(&:to_s)
118
+ shoryuken_options_hash['queue'].map!(&:to_s)
82
119
  when Symbol
83
- @shoryuken_options['queue'] = @shoryuken_options['queue'].to_s
120
+ shoryuken_options_hash['queue'] = shoryuken_options_hash['queue'].to_s
84
121
  end
85
122
 
86
- [@shoryuken_options['queue']].flatten.compact.each(&method(:register_worker))
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', '> 2'
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
- with(wait_time_seconds: 10, max_number_of_messages: limit, message_attribute_names: ['All'], attribute_names: ['All']).
32
- and_return([])
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
- with(max_number_of_messages: described_class::FETCH_LIMIT, attribute_names: ['All'], message_attribute_names: ['All']).
46
- and_return([])
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, 'Pablo', recorder
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[Pablo before], %w[Pablo after]]
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, 'Pablo', recorder
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