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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +90 -24
  3. data/.travis.yml +17 -5
  4. data/CHANGELOG.md +265 -62
  5. data/Gemfile +9 -1
  6. data/Gemfile.aws-sdk-core-v2 +13 -0
  7. data/README.md +19 -113
  8. data/Rakefile +1 -1
  9. data/bin/cli/base.rb +0 -3
  10. data/bin/cli/sqs.rb +42 -16
  11. data/bin/shoryuken +4 -9
  12. data/examples/bootstrap_queues.rb +3 -3
  13. data/examples/default_worker.rb +2 -2
  14. data/lib/shoryuken/body_parser.rb +27 -0
  15. data/lib/shoryuken/client.rb +6 -2
  16. data/lib/shoryuken/core_ext.rb +1 -1
  17. data/lib/shoryuken/default_worker_registry.rb +2 -2
  18. data/lib/shoryuken/environment_loader.rb +60 -24
  19. data/lib/shoryuken/extensions/active_job_adapter.rb +21 -11
  20. data/lib/shoryuken/fetcher.rb +58 -19
  21. data/lib/shoryuken/launcher.rb +70 -7
  22. data/lib/shoryuken/logging.rb +1 -6
  23. data/lib/shoryuken/manager.rb +50 -80
  24. data/lib/shoryuken/middleware/chain.rb +4 -0
  25. data/lib/shoryuken/middleware/server/active_record.rb +1 -1
  26. data/lib/shoryuken/middleware/server/auto_delete.rb +4 -9
  27. data/lib/shoryuken/middleware/server/auto_extend_visibility.rb +6 -9
  28. data/lib/shoryuken/middleware/server/exponential_backoff_retry.rb +9 -3
  29. data/lib/shoryuken/middleware/server/timing.rb +12 -16
  30. data/lib/shoryuken/options.rb +225 -0
  31. data/lib/shoryuken/polling/base.rb +67 -0
  32. data/lib/shoryuken/polling/strict_priority.rb +77 -0
  33. data/lib/shoryuken/polling/weighted_round_robin.rb +66 -0
  34. data/lib/shoryuken/processor.rb +30 -39
  35. data/lib/shoryuken/queue.rb +41 -10
  36. data/lib/shoryuken/runner.rb +13 -17
  37. data/lib/shoryuken/util.rb +3 -3
  38. data/lib/shoryuken/version.rb +1 -1
  39. data/lib/shoryuken/worker/default_executor.rb +33 -0
  40. data/lib/shoryuken/worker/inline_executor.rb +37 -0
  41. data/lib/shoryuken/worker.rb +76 -31
  42. data/lib/shoryuken/worker_registry.rb +4 -4
  43. data/lib/shoryuken.rb +54 -173
  44. data/shoryuken.gemspec +6 -6
  45. data/spec/integration/launcher_spec.rb +14 -8
  46. data/spec/shoryuken/body_parser_spec.rb +89 -0
  47. data/spec/shoryuken/client_spec.rb +1 -1
  48. data/spec/shoryuken/core_ext_spec.rb +6 -6
  49. data/spec/shoryuken/default_worker_registry_spec.rb +2 -4
  50. data/spec/shoryuken/environment_loader_spec.rb +32 -12
  51. data/spec/shoryuken/extensions/active_job_adapter_spec.rb +64 -0
  52. data/spec/shoryuken/fetcher_spec.rb +101 -18
  53. data/spec/shoryuken/manager_spec.rb +54 -26
  54. data/spec/shoryuken/middleware/chain_spec.rb +17 -5
  55. data/spec/shoryuken/middleware/server/auto_delete_spec.rb +9 -7
  56. data/spec/shoryuken/middleware/server/auto_extend_visibility_spec.rb +4 -4
  57. data/spec/shoryuken/middleware/server/exponential_backoff_retry_spec.rb +6 -4
  58. data/spec/shoryuken/middleware/server/timing_spec.rb +5 -3
  59. data/spec/shoryuken/options_spec.rb +180 -0
  60. data/spec/shoryuken/{polling_spec.rb → polling/strict_priority_spec.rb} +2 -101
  61. data/spec/shoryuken/polling/weighted_round_robin_spec.rb +99 -0
  62. data/spec/shoryuken/processor_spec.rb +26 -127
  63. data/spec/shoryuken/queue_spec.rb +115 -41
  64. data/spec/shoryuken/runner_spec.rb +3 -4
  65. data/spec/shoryuken/util_spec.rb +24 -0
  66. data/spec/shoryuken/worker/default_executor_spec.rb +105 -0
  67. data/spec/shoryuken/worker/inline_executor_spec.rb +49 -0
  68. data/spec/shoryuken/worker_spec.rb +35 -96
  69. data/spec/shoryuken_spec.rb +0 -59
  70. data/spec/spec_helper.rb +14 -3
  71. data/test_workers/endless_interruptive_worker.rb +2 -2
  72. data/test_workers/endless_uninterruptive_worker.rb +4 -4
  73. metadata +31 -12
  74. data/lib/shoryuken/polling.rb +0 -204
data/spec/spec_helper.rb CHANGED
@@ -5,6 +5,7 @@ require 'pry-byebug'
5
5
  require 'shoryuken'
6
6
  require 'json'
7
7
  require 'dotenv'
8
+ require 'securerandom'
8
9
  Dotenv.load
9
10
 
10
11
  if ENV['CODECLIMATE_REPO_TOKEN']
@@ -12,7 +13,7 @@ if ENV['CODECLIMATE_REPO_TOKEN']
12
13
  SimpleCov.start
13
14
  end
14
15
 
15
- config_file = File.join(File.expand_path('../..', __FILE__), 'spec', 'shoryuken.yml')
16
+ config_file = File.join(File.expand_path('..', __dir__), 'spec', 'shoryuken.yml')
16
17
 
17
18
  Shoryuken::EnvironmentLoader.setup_options(config_file: config_file)
18
19
 
@@ -31,14 +32,15 @@ RSpec.configure do |config|
31
32
  # The AWS_ACCESS_KEY_ID checker is because Travis CI
32
33
  # does not expose ENV variables to pull requests from forked repositories
33
34
  # http://docs.travis-ci.com/user/pull-requests/
34
- config.filter_run_excluding slow: true if ENV['SPEC_ALL'] != 'true' || ENV['AWS_ACCESS_KEY_ID'].nil?
35
+ # config.filter_run_excluding slow: true if ENV['SPEC_ALL'] != 'true' || ENV['AWS_ACCESS_KEY_ID'].nil?
36
+ config.filter_run_excluding slow: true
35
37
 
36
38
  config.before do
37
39
  Shoryuken::Client.class_variable_set :@@queues, {}
38
40
 
39
41
  Shoryuken::Client.sqs = nil
40
42
 
41
- Shoryuken.queues.clear
43
+ Shoryuken.groups.clear
42
44
 
43
45
  Shoryuken.options[:concurrency] = 1
44
46
  Shoryuken.options[:delay] = 1
@@ -50,7 +52,16 @@ RSpec.configure do |config|
50
52
  TestWorker.get_shoryuken_options.clear
51
53
  TestWorker.get_shoryuken_options['queue'] = 'default'
52
54
 
55
+ Shoryuken.active_job_queue_name_prefixing = false
56
+
53
57
  Shoryuken.worker_registry.clear
54
58
  Shoryuken.register_worker('default', TestWorker)
59
+
60
+ Aws.config[:stub_responses] = true
61
+
62
+ Shoryuken.sqs_client_receive_message_opts.clear
63
+
64
+ allow(Concurrent).to receive(:global_io_executor).and_return(Concurrent::ImmediateExecutor.new)
65
+ allow(Shoryuken).to receive(:active_job?).and_return(false)
55
66
  end
56
67
  end
@@ -12,7 +12,7 @@ class EndlessInterruptiveWorker
12
12
  end
13
13
 
14
14
  def max_execution_time
15
- ENV["MAX_EXECUTION_TIME"] ? ENV["MAX_EXECUTION_TIME"].to_i : 100
15
+ ENV['MAX_EXECUTION_TIME'] ? ENV['MAX_EXECUTION_TIME'].to_i : 100
16
16
  end
17
17
 
18
18
  def rng
@@ -25,7 +25,7 @@ class EndlessInterruptiveWorker
25
25
  end
26
26
  end
27
27
 
28
- def perform(sqs_msg, body)
28
+ def perform(_sqs_msg, body)
29
29
  Shoryuken.logger.info("Received message: '#{body}'")
30
30
 
31
31
  execution_ms = self.class.random_number(self.class.max_execution_time)
@@ -12,7 +12,7 @@ class EndlessUninterruptiveWorker
12
12
  end
13
13
 
14
14
  def max_execution_time
15
- ENV["MAX_EXECUTION_TIME"] ? ENV["MAX_EXECUTION_TIME"].to_i : 100
15
+ ENV['MAX_EXECUTION_TIME'] ? ENV['MAX_EXECUTION_TIME'].to_i : 100
16
16
  end
17
17
 
18
18
  def rng
@@ -25,13 +25,13 @@ class EndlessUninterruptiveWorker
25
25
  end
26
26
  end
27
27
 
28
- def perform(sqs_msg, body)
29
- Shoryuken.logger.info("Received message: '#{body}'")
28
+ def perform(_sqs_msg, body)
29
+ Shoryuken.logger.info("Received message: #{body}")
30
30
 
31
31
  execution_ms = self.class.random_number(self.class.max_execution_time)
32
32
  Shoryuken.logger.info("Going to burn metal for #{execution_ms}ms")
33
33
  end_time = Time.now + execution_ms.to_f / 1000
34
- while Time.now < end_time do
34
+ while Time.now < end_time
35
35
  # burn metal
36
36
  end
37
37
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shoryuken
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.6
4
+ version: 4.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: 2017-04-11 00:00:00.000000000 Z
11
+ date: 2018-11-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -25,7 +25,7 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.6'
27
27
  - !ruby/object:Gem::Dependency
28
- name: rake
28
+ name: dotenv
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
@@ -39,7 +39,7 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: rspec
42
+ name: pry-byebug
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
@@ -53,7 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: pry-byebug
56
+ name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -67,7 +67,7 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: dotenv
70
+ name: rspec
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - ">="
@@ -84,14 +84,14 @@ dependencies:
84
84
  name: aws-sdk-core
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - "~>"
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
89
  version: '2'
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - "~>"
94
+ - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '2'
97
97
  - !ruby/object:Gem::Dependency
@@ -137,6 +137,7 @@ files:
137
137
  - ".travis.yml"
138
138
  - CHANGELOG.md
139
139
  - Gemfile
140
+ - Gemfile.aws-sdk-core-v2
140
141
  - LICENSE
141
142
  - README.md
142
143
  - Rakefile
@@ -146,6 +147,7 @@ files:
146
147
  - examples/bootstrap_queues.rb
147
148
  - examples/default_worker.rb
148
149
  - lib/shoryuken.rb
150
+ - lib/shoryuken/body_parser.rb
149
151
  - lib/shoryuken/client.rb
150
152
  - lib/shoryuken/core_ext.rb
151
153
  - lib/shoryuken/default_worker_registry.rb
@@ -162,22 +164,29 @@ files:
162
164
  - lib/shoryuken/middleware/server/auto_extend_visibility.rb
163
165
  - lib/shoryuken/middleware/server/exponential_backoff_retry.rb
164
166
  - lib/shoryuken/middleware/server/timing.rb
165
- - lib/shoryuken/polling.rb
167
+ - lib/shoryuken/options.rb
168
+ - lib/shoryuken/polling/base.rb
169
+ - lib/shoryuken/polling/strict_priority.rb
170
+ - lib/shoryuken/polling/weighted_round_robin.rb
166
171
  - lib/shoryuken/processor.rb
167
172
  - lib/shoryuken/queue.rb
168
173
  - lib/shoryuken/runner.rb
169
174
  - lib/shoryuken/util.rb
170
175
  - lib/shoryuken/version.rb
171
176
  - lib/shoryuken/worker.rb
177
+ - lib/shoryuken/worker/default_executor.rb
178
+ - lib/shoryuken/worker/inline_executor.rb
172
179
  - lib/shoryuken/worker_registry.rb
173
180
  - shoryuken.gemspec
174
181
  - shoryuken.jpg
175
182
  - spec/integration/launcher_spec.rb
176
183
  - spec/shoryuken.yml
184
+ - spec/shoryuken/body_parser_spec.rb
177
185
  - spec/shoryuken/client_spec.rb
178
186
  - spec/shoryuken/core_ext_spec.rb
179
187
  - spec/shoryuken/default_worker_registry_spec.rb
180
188
  - spec/shoryuken/environment_loader_spec.rb
189
+ - spec/shoryuken/extensions/active_job_adapter_spec.rb
181
190
  - spec/shoryuken/fetcher_spec.rb
182
191
  - spec/shoryuken/manager_spec.rb
183
192
  - spec/shoryuken/middleware/chain_spec.rb
@@ -185,11 +194,15 @@ files:
185
194
  - spec/shoryuken/middleware/server/auto_extend_visibility_spec.rb
186
195
  - spec/shoryuken/middleware/server/exponential_backoff_retry_spec.rb
187
196
  - spec/shoryuken/middleware/server/timing_spec.rb
188
- - spec/shoryuken/polling_spec.rb
197
+ - spec/shoryuken/options_spec.rb
198
+ - spec/shoryuken/polling/strict_priority_spec.rb
199
+ - spec/shoryuken/polling/weighted_round_robin_spec.rb
189
200
  - spec/shoryuken/processor_spec.rb
190
201
  - spec/shoryuken/queue_spec.rb
191
202
  - spec/shoryuken/runner_spec.rb
192
203
  - spec/shoryuken/util_spec.rb
204
+ - spec/shoryuken/worker/default_executor_spec.rb
205
+ - spec/shoryuken/worker/inline_executor_spec.rb
193
206
  - spec/shoryuken/worker_spec.rb
194
207
  - spec/shoryuken_spec.rb
195
208
  - spec/spec_helper.rb
@@ -215,17 +228,19 @@ required_rubygems_version: !ruby/object:Gem::Requirement
215
228
  version: '0'
216
229
  requirements: []
217
230
  rubyforge_project:
218
- rubygems_version: 2.6.8
231
+ rubygems_version: 2.5.2
219
232
  signing_key:
220
233
  specification_version: 4
221
234
  summary: Shoryuken is a super efficient AWS SQS thread based message processor
222
235
  test_files:
223
236
  - spec/integration/launcher_spec.rb
224
237
  - spec/shoryuken.yml
238
+ - spec/shoryuken/body_parser_spec.rb
225
239
  - spec/shoryuken/client_spec.rb
226
240
  - spec/shoryuken/core_ext_spec.rb
227
241
  - spec/shoryuken/default_worker_registry_spec.rb
228
242
  - spec/shoryuken/environment_loader_spec.rb
243
+ - spec/shoryuken/extensions/active_job_adapter_spec.rb
229
244
  - spec/shoryuken/fetcher_spec.rb
230
245
  - spec/shoryuken/manager_spec.rb
231
246
  - spec/shoryuken/middleware/chain_spec.rb
@@ -233,11 +248,15 @@ test_files:
233
248
  - spec/shoryuken/middleware/server/auto_extend_visibility_spec.rb
234
249
  - spec/shoryuken/middleware/server/exponential_backoff_retry_spec.rb
235
250
  - spec/shoryuken/middleware/server/timing_spec.rb
236
- - spec/shoryuken/polling_spec.rb
251
+ - spec/shoryuken/options_spec.rb
252
+ - spec/shoryuken/polling/strict_priority_spec.rb
253
+ - spec/shoryuken/polling/weighted_round_robin_spec.rb
237
254
  - spec/shoryuken/processor_spec.rb
238
255
  - spec/shoryuken/queue_spec.rb
239
256
  - spec/shoryuken/runner_spec.rb
240
257
  - spec/shoryuken/util_spec.rb
258
+ - spec/shoryuken/worker/default_executor_spec.rb
259
+ - spec/shoryuken/worker/inline_executor_spec.rb
241
260
  - spec/shoryuken/worker_spec.rb
242
261
  - spec/shoryuken_spec.rb
243
262
  - spec/spec_helper.rb
@@ -1,204 +0,0 @@
1
- module Shoryuken
2
- module Polling
3
- QueueConfiguration = Struct.new(:name, :options) do
4
- def hash
5
- name.hash
6
- end
7
-
8
- def ==(other)
9
- case other
10
- when String
11
- if options.empty?
12
- name == other
13
- else
14
- false
15
- end
16
- else
17
- super
18
- end
19
- end
20
-
21
- alias_method :eql?, :==
22
-
23
- def to_s
24
- if options.empty?
25
- name
26
- else
27
- "#<QueueConfiguration #{name} options=#{options.inspect}>"
28
- end
29
- end
30
- end
31
-
32
- class BaseStrategy
33
- include Util
34
-
35
- def next_queue
36
- fail NotImplementedError
37
- end
38
-
39
- def messages_found(queue, messages_found)
40
- fail NotImplementedError
41
- end
42
-
43
- def active_queues
44
- fail NotImplementedError
45
- end
46
-
47
- def ==(other)
48
- case other
49
- when Array
50
- @queues == other
51
- else
52
- if other.respond_to?(:active_queues)
53
- active_queues == other.active_queues
54
- else
55
- false
56
- end
57
- end
58
- end
59
-
60
- private
61
-
62
- def delay
63
- Shoryuken.options[:delay].to_f
64
- end
65
- end
66
-
67
- class WeightedRoundRobin < BaseStrategy
68
- def initialize(queues)
69
- @initial_queues = queues
70
- @queues = queues.dup.uniq
71
- @paused_queues = []
72
- end
73
-
74
- def next_queue
75
- unpause_queues
76
- queue = @queues.shift
77
- return nil if queue.nil?
78
-
79
- @queues << queue
80
- QueueConfiguration.new(queue, {})
81
- end
82
-
83
- def messages_found(queue, messages_found)
84
- if messages_found == 0
85
- pause(queue)
86
- return
87
- end
88
-
89
- maximum_weight = maximum_queue_weight(queue)
90
- current_weight = current_queue_weight(queue)
91
- if maximum_weight > current_weight
92
- logger.info { "Increasing '#{queue}' weight to #{current_weight + 1}, max: #{maximum_weight}" }
93
- @queues << queue
94
- end
95
- end
96
-
97
- def active_queues
98
- unparse_queues(@queues)
99
- end
100
-
101
- private
102
-
103
- def pause(queue)
104
- return unless @queues.delete(queue)
105
- @paused_queues << [Time.now + delay, queue]
106
- logger.debug "Paused '#{queue}'"
107
- end
108
-
109
- def unpause_queues
110
- return if @paused_queues.empty?
111
- return if Time.now < @paused_queues.first[0]
112
- pause = @paused_queues.shift
113
- @queues << pause[1]
114
- logger.debug "Unpaused '#{pause[1]}'"
115
- end
116
-
117
- def current_queue_weight(queue)
118
- queue_weight(@queues, queue)
119
- end
120
-
121
- def maximum_queue_weight(queue)
122
- queue_weight(@initial_queues, queue)
123
- end
124
-
125
- def queue_weight(queues, queue)
126
- queues.count { |q| q == queue }
127
- end
128
- end
129
-
130
- class StrictPriority < BaseStrategy
131
- def initialize(queues)
132
- # Priority ordering of the queues, highest priority first
133
- @queues = queues
134
- .group_by { |q| q }
135
- .sort_by { |_, qs| -qs.count }
136
- .map(&:first)
137
-
138
- # Pause status of the queues, default to past time (unpaused)
139
- @paused_until = queues
140
- .each_with_object(Hash.new) { |queue, h| h[queue] = Time.at(0) }
141
-
142
- # Start queues at 0
143
- reset_next_queue
144
- end
145
-
146
- def next_queue
147
- next_queue = next_active_queue
148
- next_queue.nil? ? nil : QueueConfiguration.new(next_queue, {})
149
- end
150
-
151
- def messages_found(queue, messages_found)
152
- if messages_found == 0
153
- pause(queue)
154
- else
155
- reset_next_queue
156
- end
157
- end
158
-
159
- def active_queues
160
- @queues
161
- .reverse
162
- .map.with_index(1)
163
- .reject { |q, _| queue_paused?(q) }
164
- .reverse
165
- end
166
-
167
- private
168
-
169
- def next_active_queue
170
- reset_next_queue if queues_unpaused_since?
171
-
172
- size = @queues.length
173
- size.times do
174
- queue = @queues[@next_queue_index]
175
- @next_queue_index = (@next_queue_index + 1) % size
176
- return queue unless queue_paused?(queue)
177
- end
178
-
179
- nil
180
- end
181
-
182
- def queues_unpaused_since?
183
- last = @last_unpause_check
184
- now = @last_unpause_check = Time.now
185
-
186
- last && @paused_until.values.any? { |t| t > last && t <= now }
187
- end
188
-
189
- def reset_next_queue
190
- @next_queue_index = 0
191
- end
192
-
193
- def queue_paused?(queue)
194
- @paused_until[queue] > Time.now
195
- end
196
-
197
- def pause(queue)
198
- return unless delay > 0
199
- @paused_until[queue] = Time.now + delay
200
- logger.debug "Paused '#{queue}'"
201
- end
202
- end
203
- end
204
- end