shoryuken 3.0.11 → 3.1.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/.travis.yml +1 -0
- data/CHANGELOG.md +13 -2
- data/Gemfile +1 -0
- data/README.md +15 -110
- data/bin/cli/sqs.rb +7 -0
- data/lib/shoryuken.rb +39 -173
- data/lib/shoryuken/default_worker_registry.rb +2 -2
- data/lib/shoryuken/environment_loader.rb +25 -9
- data/lib/shoryuken/fetcher.rb +17 -16
- data/lib/shoryuken/launcher.rb +86 -7
- data/lib/shoryuken/manager.rb +38 -79
- data/lib/shoryuken/options.rb +192 -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 +21 -18
- data/lib/shoryuken/runner.rb +3 -15
- data/lib/shoryuken/version.rb +1 -1
- data/spec/integration/launcher_spec.rb +12 -6
- data/spec/shoryuken/environment_loader_spec.rb +3 -12
- data/spec/shoryuken/fetcher_spec.rb +30 -15
- data/spec/shoryuken/manager_spec.rb +9 -17
- data/spec/shoryuken/options_spec.rb +100 -0
- data/spec/shoryuken/{polling_spec.rb → polling/strict_priority_spec.rb} +1 -100
- data/spec/shoryuken/polling/weighted_round_robin_spec.rb +99 -0
- data/spec/shoryuken/processor_spec.rb +20 -39
- data/spec/shoryuken/runner_spec.rb +3 -4
- data/spec/shoryuken_spec.rb +0 -59
- data/spec/spec_helper.rb +7 -2
- metadata +12 -5
- data/lib/shoryuken/polling.rb +0 -204
@@ -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_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
|
data/spec/spec_helper.rb
CHANGED
@@ -32,14 +32,15 @@ RSpec.configure do |config|
|
|
32
32
|
# The AWS_ACCESS_KEY_ID checker is because Travis CI
|
33
33
|
# does not expose ENV variables to pull requests from forked repositories
|
34
34
|
# http://docs.travis-ci.com/user/pull-requests/
|
35
|
-
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
|
36
37
|
|
37
38
|
config.before do
|
38
39
|
Shoryuken::Client.class_variable_set :@@queues, {}
|
39
40
|
|
40
41
|
Shoryuken::Client.sqs = nil
|
41
42
|
|
42
|
-
Shoryuken.
|
43
|
+
Shoryuken.groups.clear
|
43
44
|
|
44
45
|
Shoryuken.options[:concurrency] = 1
|
45
46
|
Shoryuken.options[:delay] = 1
|
@@ -53,5 +54,9 @@ RSpec.configure do |config|
|
|
53
54
|
|
54
55
|
Shoryuken.worker_registry.clear
|
55
56
|
Shoryuken.register_worker('default', TestWorker)
|
57
|
+
|
58
|
+
Aws.config[:stub_responses] = true
|
59
|
+
|
60
|
+
allow(Concurrent).to receive(:global_io_executor).and_return(Concurrent::ImmediateExecutor.new)
|
56
61
|
end
|
57
62
|
end
|
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
|
4
|
+
version: 3.1.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-
|
11
|
+
date: 2017-07-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -162,7 +162,10 @@ files:
|
|
162
162
|
- lib/shoryuken/middleware/server/auto_extend_visibility.rb
|
163
163
|
- lib/shoryuken/middleware/server/exponential_backoff_retry.rb
|
164
164
|
- lib/shoryuken/middleware/server/timing.rb
|
165
|
-
- lib/shoryuken/
|
165
|
+
- lib/shoryuken/options.rb
|
166
|
+
- lib/shoryuken/polling/base.rb
|
167
|
+
- lib/shoryuken/polling/strict_priority.rb
|
168
|
+
- lib/shoryuken/polling/weighted_round_robin.rb
|
166
169
|
- lib/shoryuken/processor.rb
|
167
170
|
- lib/shoryuken/queue.rb
|
168
171
|
- lib/shoryuken/runner.rb
|
@@ -185,7 +188,9 @@ files:
|
|
185
188
|
- spec/shoryuken/middleware/server/auto_extend_visibility_spec.rb
|
186
189
|
- spec/shoryuken/middleware/server/exponential_backoff_retry_spec.rb
|
187
190
|
- spec/shoryuken/middleware/server/timing_spec.rb
|
188
|
-
- spec/shoryuken/
|
191
|
+
- spec/shoryuken/options_spec.rb
|
192
|
+
- spec/shoryuken/polling/strict_priority_spec.rb
|
193
|
+
- spec/shoryuken/polling/weighted_round_robin_spec.rb
|
189
194
|
- spec/shoryuken/processor_spec.rb
|
190
195
|
- spec/shoryuken/queue_spec.rb
|
191
196
|
- spec/shoryuken/runner_spec.rb
|
@@ -233,7 +238,9 @@ test_files:
|
|
233
238
|
- spec/shoryuken/middleware/server/auto_extend_visibility_spec.rb
|
234
239
|
- spec/shoryuken/middleware/server/exponential_backoff_retry_spec.rb
|
235
240
|
- spec/shoryuken/middleware/server/timing_spec.rb
|
236
|
-
- spec/shoryuken/
|
241
|
+
- spec/shoryuken/options_spec.rb
|
242
|
+
- spec/shoryuken/polling/strict_priority_spec.rb
|
243
|
+
- spec/shoryuken/polling/weighted_round_robin_spec.rb
|
237
244
|
- spec/shoryuken/processor_spec.rb
|
238
245
|
- spec/shoryuken/queue_spec.rb
|
239
246
|
- spec/shoryuken/runner_spec.rb
|
data/lib/shoryuken/polling.rb
DELETED
@@ -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
|