shoryuken 4.0.3 → 5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bd77c85674d135c91607fd5d422af325a2eea48b6e6bd7039b0d2c63cd6f0094
4
- data.tar.gz: 41909fd74b45cc2dbb3c1cfced6717299e0819e960210c741d3c468e8f4fa569
3
+ metadata.gz: ce36f4dac1c75e383185df15db196aec57c968dda1a5823b8d944ad4a9675906
4
+ data.tar.gz: a460a585e97a6c0a3432f6b28bec254d494900672a06bffbd7461e830a8de0cf
5
5
  SHA512:
6
- metadata.gz: 1e10d6ca93d95bd1fccd6da3dd05df596db6fc5613a5a7d56c83ff6bb3db08202780939fd847d4a54db932f289a553706e8290ead58a174b982f036b524c8b46
7
- data.tar.gz: 5abaac5fdd7c5c5ea1e512ee13757a25491da1c8999e3fc8001b9d5465023e511d7754224d684f1c7b16014c85d9019533bec86d1740fe0da54c7d9d4b97adab
6
+ metadata.gz: 833bab295345b25456f617f36e4ec2f2cfd0d823a01ddb87d8f528597ab79b91ce0ae8c67b47ffc2a9d1400f0a5cf62df3125fbdfbb49abd3a5e4a5eb3b7b0ee
7
+ data.tar.gz: 91a4355cd9e180f006e8768bde9627c1df9cf0057d294bdfcb422f479de2ef1784aa5b904c7b97dac8ed7bb7b9879bdea56eb4cd00d51ff456d3b4555f88c991
data/.rubocop.yml CHANGED
@@ -1,7 +1,7 @@
1
1
  AllCops:
2
2
  Exclude:
3
3
  - '**/Gemfile'
4
- TargetRubyVersion: 2.1
4
+ TargetRubyVersion: 2.3
5
5
 
6
6
  Metrics/PerceivedComplexity:
7
7
  Enabled: false
data/.travis.yml CHANGED
@@ -3,10 +3,11 @@ language: ruby
3
3
  rvm:
4
4
  - 2.0.0
5
5
  - 2.1.10
6
- - 2.2.9
7
- - 2.3.6
8
- - 2.4.3
9
- - 2.5.0
6
+ - 2.2.10
7
+ - 2.3.8
8
+ - 2.4.4
9
+ - 2.5.1
10
+ - 2.6.3
10
11
 
11
12
  notifications:
12
13
  email:
@@ -23,7 +24,7 @@ env:
23
24
  script: bundle exec rspec spec
24
25
 
25
26
  before_install:
26
- - gem update bundler
27
+ - gem install bundler -v '< 2'
27
28
 
28
29
  after_success:
29
30
  - bundle exec codeclimate-test-reporter
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ ## [v5.0.0] - 2019-06-18
2
+
3
+ - Fix bug where empty queues were not paused in batch processing mode
4
+ - [#569](https://github.com/phstc/shoryuken/pull/569)
5
+
6
+ - Preserve batch limit when receiving messages from a FIFO queue
7
+ - [#563](https://github.com/phstc/shoryuken/pull/563)
8
+
9
+ - Replace static options with instance options
10
+ - [#534](https://github.com/phstc/shoryuken/pull/534)
11
+
1
12
  ## [v4.0.3] - 2019-01-06
2
13
 
3
14
  - Support delay per processing group
data/lib/shoryuken.rb CHANGED
@@ -41,8 +41,12 @@ require 'shoryuken/options'
41
41
  module Shoryuken
42
42
  extend SingleForwardable
43
43
 
44
+ def self.shoryuken_options
45
+ @_shoryuken_options ||= Shoryuken::Options.new
46
+ end
47
+
44
48
  def_delegators(
45
- :'Shoryuken::Options',
49
+ :shoryuken_options,
46
50
  :active_job?,
47
51
  :add_group,
48
52
  :groups,
@@ -59,7 +63,7 @@ module Shoryuken
59
63
  :start_callback=,
60
64
  :stop_callback,
61
65
  :stop_callback=,
62
- :active_job_queue_name_prefixing,
66
+ :active_job_queue_name_prefixing?,
63
67
  :active_job_queue_name_prefixing=,
64
68
  :sqs_client,
65
69
  :sqs_client=,
@@ -79,7 +83,8 @@ module Shoryuken
79
83
  :on_stop,
80
84
  :on,
81
85
  :cache_visibility_timeout?,
82
- :cache_visibility_timeout=
86
+ :cache_visibility_timeout=,
87
+ :delay
83
88
  )
84
89
  end
85
90
 
@@ -99,7 +99,7 @@ module Shoryuken
99
99
 
100
100
  def prefix_active_job_queue_names
101
101
  return unless Shoryuken.active_job?
102
- return unless Shoryuken.active_job_queue_name_prefixing
102
+ return unless Shoryuken.active_job_queue_name_prefixing?
103
103
 
104
104
  Shoryuken.options[:queues].to_a.map! do |queue_name, weight|
105
105
  prefix_active_job_queue_name(queue_name, weight)
@@ -14,7 +14,7 @@ module Shoryuken
14
14
 
15
15
  logger.debug { "Looking for new messages in #{queue}" }
16
16
 
17
- sqs_msgs = Array(receive_messages(queue, [FETCH_LIMIT, limit].min))
17
+ sqs_msgs = Array(receive_messages(queue, limit))
18
18
 
19
19
  logger.debug { "Found #{sqs_msgs.size} messages for #{queue.name}" } unless sqs_msgs.empty?
20
20
  logger.debug { "Fetcher for #{queue} completed in #{elapsed(started_at)} ms" }
@@ -49,16 +49,7 @@ module Shoryuken
49
49
 
50
50
  shoryuken_queue = Shoryuken::Client.queues(queue.name)
51
51
 
52
- # For FIFO queues we want to make sure we process one message per group at the time
53
- # if we set max_number_of_messages greater than 1,
54
- # SQS may return more than one message for the same message group
55
- # since Shoryuken uses threads, it will try to process more than one at once
56
- # > The message group ID is the tag that specifies that a message belongs to a specific message group.
57
- # > Messages that belong to the same message group are always processed one by one,
58
- # > in a strict order relative to the message group
59
- # > (however, messages that belong to different message groups might be processed out of order).
60
- # > https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/using-messagegroupid-property.html
61
- options[:max_number_of_messages] = shoryuken_queue.fifo? ? 1 : max_number_of_messages(limit, options)
52
+ options[:max_number_of_messages] = max_number_of_messages(shoryuken_queue, limit, options)
62
53
  options[:message_attribute_names] = %w[All]
63
54
  options[:attribute_names] = %w[All]
64
55
 
@@ -67,7 +58,18 @@ module Shoryuken
67
58
  shoryuken_queue.receive_messages(options)
68
59
  end
69
60
 
70
- def max_number_of_messages(limit, options)
61
+ def max_number_of_messages(shoryuken_queue, limit, options)
62
+ # For FIFO queues we want to make sure we process one message per group at a time
63
+ # if we set max_number_of_messages greater than 1,
64
+ # SQS may return more than one message for the same message group
65
+ # since Shoryuken uses threads, it will try to process more than one message at once
66
+ # > The message group ID is the tag that specifies that a message belongs to a specific message group.
67
+ # > Messages that belong to the same message group are always processed one by one,
68
+ # > in a strict order relative to the message group
69
+ # > (however, messages that belong to different message groups might be processed out of order).
70
+ # > https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/using-messagegroupid-property.html
71
+ limit = 1 if shoryuken_queue.fifo? && !batched_queue?(shoryuken_queue)
72
+
71
73
  [limit, FETCH_LIMIT, options[:max_number_of_messages]].compact.min
72
74
  end
73
75
 
@@ -77,5 +79,9 @@ module Shoryuken
77
79
 
78
80
  options.to_h.dup
79
81
  end
82
+
83
+ def batched_queue?(queue)
84
+ Shoryuken.worker_registry.batch_receive_messages?(queue.name)
85
+ end
80
86
  end
81
- end
87
+ end
@@ -72,7 +72,7 @@ module Shoryuken
72
72
  Shoryuken.groups.map do |group, options|
73
73
  Shoryuken::Manager.new(
74
74
  Shoryuken::Fetcher.new(group),
75
- Shoryuken.polling_strategy(group).new(options[:queues], Shoryuken::Options.delay(group)),
75
+ Shoryuken.polling_strategy(group).new(options[:queues], Shoryuken.delay(group)),
76
76
  options[:concurrency],
77
77
  executor
78
78
  )
@@ -43,8 +43,8 @@ module Shoryuken
43
43
  logger.debug { "Ready: #{ready}, Busy: #{busy}, Active Queues: #{@polling_strategy.active_queues}" }
44
44
 
45
45
  batched_queue?(queue) ? dispatch_batch(queue) : dispatch_single_messages(queue)
46
- rescue => ex
47
- handle_dispatch_error(ex)
46
+ rescue => e
47
+ handle_dispatch_error(e)
48
48
  ensure
49
49
  dispatch_loop
50
50
  end
@@ -74,9 +74,9 @@ module Shoryuken
74
74
  end
75
75
 
76
76
  def dispatch_batch(queue)
77
- return if (batch = @fetcher.fetch(queue, BATCH_LIMIT)).none?
77
+ batch = @fetcher.fetch(queue, BATCH_LIMIT)
78
78
  @polling_strategy.messages_found(queue.name, batch.size)
79
- assign(queue.name, patch_batch!(batch))
79
+ assign(queue.name, patch_batch!(batch)) if batch.any?
80
80
  end
81
81
 
82
82
  def dispatch_single_messages(queue)
@@ -14,228 +14,166 @@ module Shoryuken
14
14
  }
15
15
  }.freeze
16
16
 
17
- @@groups = {}
18
- @@worker_registry = DefaultWorkerRegistry.new
19
- @@active_job_queue_name_prefixing = false
20
- @@sqs_client = nil
21
- @@sqs_client_receive_message_opts = {}
22
- @@start_callback = nil
23
- @@stop_callback = nil
24
- @@worker_executor = Worker::DefaultExecutor
25
- @@launcher_executor = nil
26
- @@cache_visibility_timeout = false
27
-
28
- class << self
29
- def active_job?
30
- defined?(::ActiveJob)
31
- end
32
-
33
- def add_group(group, concurrency = nil, delay: nil)
34
- concurrency ||= options[:concurrency]
35
- delay ||= options[:delay]
36
-
37
- groups[group] ||= {
38
- concurrency: concurrency,
39
- delay: delay,
40
- queues: []
41
- }
42
- end
43
-
44
- def groups
45
- @@groups
46
- end
47
-
48
- def add_queue(queue, weight, group)
49
- weight.times do
50
- groups[group][:queues] << queue
51
- end
52
- end
53
-
54
- def ungrouped_queues
55
- groups.values.flat_map { |options| options[:queues] }
56
- end
57
-
58
- def worker_registry
59
- @@worker_registry
60
- end
61
-
62
- def worker_registry=(worker_registry)
63
- @@worker_registry = worker_registry
64
- end
65
-
66
- def worker_executor
67
- @@worker_executor
68
- end
69
-
70
- def worker_executor=(worker_executor)
71
- @@worker_executor = worker_executor
72
- end
73
-
74
- def launcher_executor
75
- @@launcher_executor
76
- end
77
-
78
- def launcher_executor=(launcher_executor)
79
- @@launcher_executor = launcher_executor
80
- end
81
-
82
- def polling_strategy(group)
83
- strategy = (group == 'default' ? options : options[:groups].to_h[group]).to_h[:polling_strategy]
84
- case strategy
85
- when 'WeightedRoundRobin', nil # Default case
86
- Polling::WeightedRoundRobin
87
- when 'StrictPriority'
88
- Polling::StrictPriority
89
- when Class
90
- strategy
91
- else
92
- raise ArgumentError, "#{strategy} is not a valid polling_strategy"
93
- end
94
- end
95
-
96
- def delay(group)
97
- groups[group].to_h.fetch(:delay, options[:delay]).to_f
98
- end
99
-
100
- def start_callback
101
- @@start_callback
102
- end
103
-
104
- def start_callback=(start_callback)
105
- @@start_callback = start_callback
106
- end
17
+ attr_accessor :active_job_queue_name_prefixing, :cache_visibility_timeout, :default_worker_options, :groups,
18
+ :launcher_executor, :sqs_client, :sqs_client_receive_message_opts,
19
+ :start_callback, :worker_executor, :worker_registry
20
+
21
+ def initialize
22
+ self.groups = {}
23
+ self.worker_registry = DefaultWorkerRegistry.new
24
+ self.active_job_queue_name_prefixing = false
25
+ self.worker_executor = Worker::DefaultExecutor
26
+ self.cache_visibility_timeout = false
27
+ # this is needed for keeping backward compatibility
28
+ @sqs_client_receive_message_opts ||= {}
29
+ end
107
30
 
108
- def stop_callback
109
- @@stop_callback
110
- end
31
+ def active_job?
32
+ defined?(::ActiveJob)
33
+ end
111
34
 
112
- def stop_callback=(stop_callback)
113
- @@stop_callback = stop_callback
114
- end
35
+ def add_group(group, concurrency = nil, delay: nil)
36
+ concurrency ||= options[:concurrency]
37
+ delay ||= options[:delay]
115
38
 
116
- def active_job_queue_name_prefixing
117
- @@active_job_queue_name_prefixing
118
- end
39
+ groups[group] ||= {
40
+ concurrency: concurrency,
41
+ delay: delay,
42
+ queues: []
43
+ }
44
+ end
119
45
 
120
- def active_job_queue_name_prefixing=(active_job_queue_name_prefixing)
121
- @@active_job_queue_name_prefixing = active_job_queue_name_prefixing
46
+ def add_queue(queue, weight, group)
47
+ weight.times do
48
+ groups[group][:queues] << queue
122
49
  end
50
+ end
123
51
 
124
- def sqs_client
125
- @@sqs_client ||= Aws::SQS::Client.new
126
- end
52
+ def ungrouped_queues
53
+ groups.values.flat_map { |options| options[:queues] }
54
+ end
127
55
 
128
- def sqs_client=(sqs_client)
129
- @@sqs_client = sqs_client
56
+ def polling_strategy(group)
57
+ strategy = (group == 'default' ? options : options[:groups].to_h[group]).to_h[:polling_strategy]
58
+ case strategy
59
+ when 'WeightedRoundRobin', nil # Default case
60
+ Polling::WeightedRoundRobin
61
+ when 'StrictPriority'
62
+ Polling::StrictPriority
63
+ when Class
64
+ strategy
65
+ else
66
+ raise ArgumentError, "#{strategy} is not a valid polling_strategy"
130
67
  end
68
+ end
131
69
 
132
- def sqs_client_receive_message_opts
133
- @@sqs_client_receive_message_opts
134
- end
70
+ def delay(group)
71
+ groups[group].to_h.fetch(:delay, options[:delay]).to_f
72
+ end
135
73
 
136
- def sqs_client_receive_message_opts=(sqs_client_receive_message_opts)
137
- @@sqs_client_receive_message_opts['default'] = sqs_client_receive_message_opts
138
- end
74
+ def sqs_client
75
+ @sqs_client ||= Aws::SQS::Client.new
76
+ end
139
77
 
140
- def options
141
- @@options ||= DEFAULTS.dup
142
- end
78
+ def sqs_client_receive_message_opts=(sqs_client_receive_message_opts)
79
+ @sqs_client_receive_message_opts['default'] = sqs_client_receive_message_opts
80
+ end
143
81
 
144
- def logger
145
- Shoryuken::Logging.logger
146
- end
82
+ def options
83
+ @options ||= DEFAULTS.dup
84
+ end
147
85
 
148
- def register_worker(*args)
149
- @@worker_registry.register_worker(*args)
150
- end
86
+ def logger
87
+ Shoryuken::Logging.logger
88
+ end
151
89
 
152
- def configure_server
153
- yield self if server?
154
- end
90
+ def register_worker(*args)
91
+ worker_registry.register_worker(*args)
92
+ end
155
93
 
156
- def server_middleware
157
- @@server_chain ||= default_server_middleware
158
- yield @@server_chain if block_given?
159
- @@server_chain
160
- end
94
+ def configure_server
95
+ yield self if server?
96
+ end
161
97
 
162
- def configure_client
163
- yield self unless server?
164
- end
98
+ def server_middleware
99
+ @_server_chain ||= default_server_middleware
100
+ yield @_server_chain if block_given?
101
+ @_server_chain
102
+ end
165
103
 
166
- def client_middleware
167
- @@client_chain ||= default_client_middleware
168
- yield @@client_chain if block_given?
169
- @@client_chain
170
- end
104
+ def configure_client
105
+ yield self unless server?
106
+ end
171
107
 
172
- def default_worker_options
173
- @@default_worker_options ||= {
174
- 'queue' => 'default',
175
- 'delete' => false,
176
- 'auto_delete' => false,
177
- 'auto_visibility_timeout' => false,
178
- 'retry_intervals' => nil,
179
- 'batch' => false
180
- }
181
- end
108
+ def client_middleware
109
+ @_client_chain ||= default_client_middleware
110
+ yield @_client_chain if block_given?
111
+ @_client_chain
112
+ end
182
113
 
183
- def default_worker_options=(default_worker_options)
184
- @@default_worker_options = default_worker_options
185
- end
114
+ def default_worker_options
115
+ @default_worker_options ||= {
116
+ 'queue' => 'default',
117
+ 'delete' => false,
118
+ 'auto_delete' => false,
119
+ 'auto_visibility_timeout' => false,
120
+ 'retry_intervals' => nil,
121
+ 'batch' => false
122
+ }
123
+ end
186
124
 
187
- def on_start(&block)
188
- @@start_callback = block
189
- end
125
+ def on_start(&block)
126
+ self.start_callback = block
127
+ end
190
128
 
191
- def on_stop(&block)
192
- @@stop_callback = block
193
- end
129
+ def on_stop(&block)
130
+ self.stop_callback = block
131
+ end
194
132
 
195
- # Register a block to run at a point in the Shoryuken lifecycle.
196
- # :startup, :quiet or :shutdown are valid events.
197
- #
198
- # Shoryuken.configure_server do |config|
199
- # config.on(:shutdown) do
200
- # puts "Goodbye cruel world!"
201
- # end
202
- # end
203
- def on(event, &block)
204
- fail ArgumentError, "Symbols only please: #{event}" unless event.is_a?(Symbol)
205
- fail ArgumentError, "Invalid event name: #{event}" unless options[:lifecycle_events].key?(event)
206
- options[:lifecycle_events][event] << block
207
- end
133
+ # Register a block to run at a point in the Shoryuken lifecycle.
134
+ # :startup, :quiet or :shutdown are valid events.
135
+ #
136
+ # Shoryuken.configure_server do |config|
137
+ # config.on(:shutdown) do
138
+ # puts "Goodbye cruel world!"
139
+ # end
140
+ # end
141
+ def on(event, &block)
142
+ fail ArgumentError, "Symbols only please: #{event}" unless event.is_a?(Symbol)
143
+ fail ArgumentError, "Invalid event name: #{event}" unless options[:lifecycle_events].key?(event)
144
+
145
+ options[:lifecycle_events][event] << block
146
+ end
208
147
 
209
- def server?
210
- defined?(Shoryuken::CLI)
211
- end
148
+ def server?
149
+ defined?(Shoryuken::CLI)
150
+ end
212
151
 
213
- def cache_visibility_timeout?
214
- @@cache_visibility_timeout
215
- end
152
+ def cache_visibility_timeout?
153
+ @cache_visibility_timeout
154
+ end
216
155
 
217
- def cache_visibility_timeout=(cache_visibility_timeout)
218
- @@cache_visibility_timeout = cache_visibility_timeout
219
- end
156
+ def active_job_queue_name_prefixing?
157
+ @active_job_queue_name_prefixing
158
+ end
220
159
 
221
- private
222
-
223
- def default_server_middleware
224
- Middleware::Chain.new do |m|
225
- m.add Middleware::Server::Timing
226
- m.add Middleware::Server::ExponentialBackoffRetry
227
- m.add Middleware::Server::AutoDelete
228
- m.add Middleware::Server::AutoExtendVisibility
229
- if defined?(::ActiveRecord::Base)
230
- require 'shoryuken/middleware/server/active_record'
231
- m.add Middleware::Server::ActiveRecord
232
- end
160
+ private
161
+
162
+ def default_server_middleware
163
+ Middleware::Chain.new do |m|
164
+ m.add Middleware::Server::Timing
165
+ m.add Middleware::Server::ExponentialBackoffRetry
166
+ m.add Middleware::Server::AutoDelete
167
+ m.add Middleware::Server::AutoExtendVisibility
168
+ if defined?(::ActiveRecord::Base)
169
+ require 'shoryuken/middleware/server/active_record'
170
+ m.add Middleware::Server::ActiveRecord
233
171
  end
234
172
  end
173
+ end
235
174
 
236
- def default_client_middleware
237
- Middleware::Chain.new
238
- end
175
+ def default_client_middleware
176
+ Middleware::Chain.new
239
177
  end
240
178
  end
241
179
  end
@@ -66,7 +66,7 @@ module Shoryuken
66
66
  end
67
67
 
68
68
  def set_name_and_url(name_or_url)
69
- if name_or_url.start_with?('https://sqs.')
69
+ if name_or_url.include?('://')
70
70
  set_by_url(name_or_url)
71
71
 
72
72
  # anticipate the fifo? checker for validating the queue URL
@@ -1,3 +1,3 @@
1
1
  module Shoryuken
2
- VERSION = '4.0.3'.freeze
2
+ VERSION = '5.0.0'.freeze
3
3
  end
@@ -17,9 +17,9 @@ module Shoryuken
17
17
  alias_method :perform_at, :perform_in
18
18
 
19
19
  def server_middleware
20
- @server_chain ||= Shoryuken.server_middleware.dup
21
- yield @server_chain if block_given?
22
- @server_chain
20
+ @_server_chain ||= Shoryuken.server_middleware.dup
21
+ yield @_server_chain if block_given?
22
+ @_server_chain
23
23
  end
24
24
 
25
25
  def shoryuken_options(opts = {})
data/shoryuken.gemspec CHANGED
@@ -17,7 +17,6 @@ Gem::Specification.new do |spec|
17
17
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
18
  spec.require_paths = ['lib']
19
19
 
20
- spec.add_development_dependency 'bundler', '~> 1.6'
21
20
  spec.add_development_dependency 'dotenv'
22
21
  spec.add_development_dependency 'pry-byebug'
23
22
  spec.add_development_dependency 'rake'
@@ -103,9 +103,9 @@ RSpec.describe Shoryuken::Fetcher do
103
103
 
104
104
  context 'when FIFO' do
105
105
  let(:limit) { 10 }
106
- let(:queue) { instance_double('Shoryuken::Queue', fifo?: true) }
106
+ let(:queue) { instance_double('Shoryuken::Queue', fifo?: true, name: queue_name) }
107
107
 
108
- it 'polls one message at the time' do
108
+ it 'polls one message at a time' do
109
109
  # see https://github.com/phstc/shoryuken/pull/530
110
110
 
111
111
  allow(Shoryuken::Client).to receive(:queues).with(queue_name).and_return(queue)
@@ -115,6 +115,21 @@ RSpec.describe Shoryuken::Fetcher do
115
115
 
116
116
  subject.fetch(queue_config, limit)
117
117
  end
118
+
119
+ context 'with batch=true' do
120
+ it 'polls the provided limit' do
121
+ # see https://github.com/phstc/shoryuken/pull/530
122
+
123
+ allow(Shoryuken::Client).to receive(:queues).with(queue_name).and_return(queue)
124
+ allow(Shoryuken.worker_registry).to receive(:batch_receive_messages?).with(queue.name).and_return(true)
125
+
126
+ expect(queue).to receive(:receive_messages).with(
127
+ max_number_of_messages: limit, attribute_names: ['All'], message_attribute_names: ['All']
128
+ ).and_return([])
129
+
130
+ subject.fetch(queue_config, limit)
131
+ end
132
+ end
118
133
  end
119
134
  end
120
135
  end
@@ -72,11 +72,27 @@ RSpec.describe Shoryuken::Manager do
72
72
  expect(fetcher).to receive(:fetch).with(q, concurrency).and_return(messages)
73
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
- expect(Shoryuken.logger).to_not receive(:info)
75
+ expect(Shoryuken.logger).to receive(:info).never
76
76
 
77
77
  subject.send(:dispatch)
78
78
  end
79
79
 
80
+ context 'and there are no messages in the queue' do
81
+ specify do
82
+ messages = %w[]
83
+ q = Shoryuken::Polling::QueueConfiguration.new(queue, {})
84
+
85
+ expect(fetcher).to receive(:fetch).with(q, concurrency).and_return(messages)
86
+ expect(subject).to receive(:fire_event).with(:dispatch, false, queue_name: q.name)
87
+ expect(polling_strategy).to receive(:messages_found).with(q.name, 0)
88
+ expect(Shoryuken.logger).to receive(:info).never
89
+ expect(Shoryuken::Processor).to receive(:process).never
90
+ expect_any_instance_of(described_class).to receive(:assign).never
91
+
92
+ subject.send(:dispatch)
93
+ end
94
+ end
95
+
80
96
  context 'when batch' do
81
97
  specify do
82
98
  messages = %w[test1 test2 test3]
@@ -86,10 +102,27 @@ RSpec.describe Shoryuken::Manager do
86
102
  expect(subject).to receive(:fire_event).with(:dispatch, false, queue_name: q.name)
87
103
  allow(subject).to receive(:batched_queue?).with(q).and_return(true)
88
104
  expect(Shoryuken::Processor).to receive(:process).with(q, messages)
89
- expect(Shoryuken.logger).to_not receive(:info)
105
+ expect(Shoryuken.logger).to receive(:info).never
90
106
 
91
107
  subject.send(:dispatch)
92
108
  end
109
+
110
+ context 'and there are no messages in the queue' do
111
+ specify do
112
+ messages = %w[]
113
+ q = Shoryuken::Polling::QueueConfiguration.new(queue, {})
114
+
115
+ expect(fetcher).to receive(:fetch).with(q, described_class::BATCH_LIMIT).and_return(messages)
116
+ expect(subject).to receive(:fire_event).with(:dispatch, false, queue_name: q.name)
117
+ allow(subject).to receive(:batched_queue?).with(q).and_return(true)
118
+ expect(polling_strategy).to receive(:messages_found).with(q.name, 0)
119
+ expect(Shoryuken.logger).to receive(:info).never
120
+ expect(Shoryuken::Processor).to receive(:process).never
121
+ expect_any_instance_of(described_class).to receive(:assign).never
122
+
123
+ subject.send(:dispatch)
124
+ end
125
+ end
93
126
  end
94
127
  end
95
128
 
@@ -1,6 +1,8 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  RSpec.describe Shoryuken::Options do
4
+ subject { Shoryuken.shoryuken_options }
5
+
4
6
  describe '.add_group adds queues and optional delay' do
5
7
  before do
6
8
  Shoryuken.groups.clear
@@ -10,14 +12,14 @@ RSpec.describe Shoryuken::Options do
10
12
  end
11
13
 
12
14
  specify do
13
- described_class.add_queue('queue1', 1, 'group1')
14
- described_class.add_queue('queue2', 2, 'group2')
15
- described_class.add_queue('queue3', 1, 'group3')
15
+ subject.add_queue('queue1', 1, 'group1')
16
+ subject.add_queue('queue2', 2, 'group2')
17
+ subject.add_queue('queue3', 1, 'group3')
16
18
 
17
- expect(described_class.groups['group1'][:queues]).to eq(%w[queue1])
18
- expect(described_class.groups['group2'][:queues]).to eq(%w[queue2 queue2])
19
- expect(described_class.groups['group3'][:queues]).to eq(%w[queue3])
20
- expect(described_class.groups['group3'][:delay]).to eq(5)
19
+ expect(subject.groups['group1'][:queues]).to eq(%w[queue1])
20
+ expect(subject.groups['group2'][:queues]).to eq(%w[queue2 queue2])
21
+ expect(subject.groups['group3'][:queues]).to eq(%w[queue3])
22
+ expect(subject.groups['group3'][:delay]).to eq(5)
21
23
  end
22
24
  end
23
25
 
@@ -25,11 +27,11 @@ RSpec.describe Shoryuken::Options do
25
27
  specify do
26
28
  Shoryuken.add_group('group1', 25)
27
29
  Shoryuken.add_group('group2', 25, delay: 5)
28
- described_class.add_queue('queue1', 1, 'group1')
29
- described_class.add_queue('queue2', 2, 'group2')
30
+ subject.add_queue('queue1', 1, 'group1')
31
+ subject.add_queue('queue2', 2, 'group2')
30
32
 
31
- expect(described_class.delay('group1')).to eq(Shoryuken.options[:delay])
32
- expect(described_class.delay('group2')).to eq(5.0)
33
+ expect(subject.delay('group1')).to eq(Shoryuken.options[:delay])
34
+ expect(subject.delay('group2')).to eq(5.0)
33
35
  end
34
36
  end
35
37
 
@@ -41,10 +43,10 @@ RSpec.describe Shoryuken::Options do
41
43
  end
42
44
 
43
45
  specify do
44
- described_class.add_queue('queue1', 1, 'group1')
45
- described_class.add_queue('queue2', 2, 'group2')
46
+ subject.add_queue('queue1', 1, 'group1')
47
+ subject.add_queue('queue2', 2, 'group2')
46
48
 
47
- expect(described_class.ungrouped_queues).to eq(%w[queue1 queue2 queue2])
49
+ expect(subject.ungrouped_queues).to eq(%w[queue1 queue2 queue2])
48
50
  end
49
51
  end
50
52
 
@@ -68,22 +70,22 @@ RSpec.describe Shoryuken::Options do
68
70
 
69
71
  describe '.register_worker' do
70
72
  it 'registers a worker' do
71
- described_class.worker_registry.clear
72
- described_class.register_worker('default', TestWorker)
73
- expect(described_class.worker_registry.workers('default')).to eq([TestWorker])
73
+ subject.worker_registry.clear
74
+ subject.register_worker('default', TestWorker)
75
+ expect(subject.worker_registry.workers('default')).to eq([TestWorker])
74
76
  end
75
77
 
76
78
  it 'registers a batchable worker' do
77
- described_class.worker_registry.clear
79
+ subject.worker_registry.clear
78
80
  TestWorker.get_shoryuken_options['batch'] = true
79
- described_class.register_worker('default', TestWorker)
80
- expect(described_class.worker_registry.workers('default')).to eq([TestWorker])
81
+ subject.register_worker('default', TestWorker)
82
+ expect(subject.worker_registry.workers('default')).to eq([TestWorker])
81
83
  end
82
84
 
83
85
  it 'allows multiple workers' do
84
- described_class.worker_registry.clear
85
- described_class.register_worker('default', TestWorker)
86
- expect(described_class.worker_registry.workers('default')).to eq([TestWorker])
86
+ subject.worker_registry.clear
87
+ subject.register_worker('default', TestWorker)
88
+ expect(subject.worker_registry.workers('default')).to eq([TestWorker])
87
89
 
88
90
  class Test2Worker
89
91
  include Shoryuken::Worker
@@ -93,13 +95,13 @@ RSpec.describe Shoryuken::Options do
93
95
  def perform(sqs_msg, body); end
94
96
  end
95
97
 
96
- expect(described_class.worker_registry.workers('default')).to eq([Test2Worker])
98
+ expect(subject.worker_registry.workers('default')).to eq([Test2Worker])
97
99
  end
98
100
 
99
101
  it 'raises an exception when mixing batchable with non batchable' do
100
- described_class.worker_registry.clear
102
+ subject.worker_registry.clear
101
103
  TestWorker.get_shoryuken_options['batch'] = true
102
- described_class.register_worker('default', TestWorker)
104
+ subject.register_worker('default', TestWorker)
103
105
 
104
106
  expect {
105
107
  class BatchableWorker
@@ -57,8 +57,8 @@ RSpec.describe Shoryuken::Processor do
57
57
 
58
58
  context 'server' do
59
59
  before do
60
- allow(Shoryuken::Options).to receive(:server?).and_return(true)
61
- WorkerCalledMiddlewareWorker.instance_variable_set(:@server_chain, nil) # un-memoize middleware
60
+ allow_any_instance_of(Shoryuken::Options).to receive(:server?).and_return(true)
61
+ WorkerCalledMiddlewareWorker.instance_variable_set(:@_server_chain, nil) # un-memoize middleware
62
62
 
63
63
  Shoryuken.configure_server do |config|
64
64
  config.server_middleware do |chain|
@@ -85,8 +85,8 @@ RSpec.describe Shoryuken::Processor do
85
85
 
86
86
  context 'client' do
87
87
  before do
88
- allow(Shoryuken).to receive(:server?).and_return(false)
89
- WorkerCalledMiddlewareWorker.instance_variable_set(:@server_chain, nil) # un-memoize middleware
88
+ allow_any_instance_of(Shoryuken::Options).to receive(:server?).and_return(false)
89
+ WorkerCalledMiddlewareWorker.instance_variable_set(:@_server_chain, nil) # un-memoize middleware
90
90
 
91
91
  Shoryuken.configure_server do |config|
92
92
  config.server_middleware do |chain|
@@ -26,6 +26,19 @@ RSpec.describe Shoryuken::Queue do
26
26
  end
27
27
  end
28
28
 
29
+ context 'when a non SQS queue URL' do
30
+ let(:queue_url) { "http://localhost:4576/queue/#{queue_name}" }
31
+
32
+ it 'instantiates by URL and validate the URL' do
33
+ # See https://github.com/phstc/shoryuken/pull/551
34
+ expect_any_instance_of(described_class).to receive(:fifo?).and_return(false)
35
+
36
+ subject = described_class.new(sqs, queue_url)
37
+
38
+ expect(subject.name).to eq(queue_name)
39
+ end
40
+ end
41
+
29
42
  context 'when queue name supplied' do
30
43
  subject { described_class.new(sqs, queue_name) }
31
44
 
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shoryuken
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.3
4
+ version: 5.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pablo Cantero
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-01-06 00:00:00.000000000 Z
11
+ date: 2019-06-18 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: bundler
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '1.6'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '1.6'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: dotenv
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -227,7 +213,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
227
213
  - !ruby/object:Gem::Version
228
214
  version: '0'
229
215
  requirements: []
230
- rubygems_version: 3.0.1
216
+ rubyforge_project:
217
+ rubygems_version: 2.7.6.2
231
218
  signing_key:
232
219
  specification_version: 4
233
220
  summary: Shoryuken is a super efficient AWS SQS thread based message processor