shoryuken 2.1.1 → 2.1.2
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/.codeclimate.yml +3 -8
- data/.travis.yml +4 -0
- data/CHANGELOG.md +19 -0
- data/README.md +62 -15
- data/lib/shoryuken.rb +3 -1
- data/lib/shoryuken/environment_loader.rb +2 -2
- data/lib/shoryuken/fetcher.rb +16 -45
- data/lib/shoryuken/launcher.rb +2 -3
- data/lib/shoryuken/manager.rb +72 -110
- data/lib/shoryuken/polling.rb +206 -0
- data/lib/shoryuken/processor.rb +8 -7
- data/lib/shoryuken/version.rb +1 -1
- data/spec/shoryuken/fetcher_spec.rb +18 -52
- data/spec/shoryuken/manager_spec.rb +63 -94
- data/spec/shoryuken/middleware/server/auto_delete_spec.rb +2 -2
- data/spec/shoryuken/middleware/server/exponential_backoff_retry_spec.rb +4 -4
- data/spec/shoryuken/polling_spec.rb +239 -0
- data/test_workers/endless_interruptive_worker.rb +41 -0
- data/test_workers/endless_uninterruptive_worker.rb +44 -0
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fd50ddb123d1c14d3ff0a0ac562c3e156afd2dfd
|
4
|
+
data.tar.gz: 9bcd1a88456f1d8454609d7440d209bc78b5a89b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 64680cf91fbf51372720f872f0ac7cced4d42e2b86c61b66137fd5993f1e58ca2ab86c907ff49eb8c464817c5c4efe53ea75e234a4ee01a4d558164535086c46
|
7
|
+
data.tar.gz: 75fbaab18cd22e600ccd6e705eef80532faf0236a434803cf0678dc14cf6b7fac30e40d0350e8be2b47eb8dd54289667eeccb12a49af0febbcafc0d5594e05f5
|
data/.codeclimate.yml
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
---
|
2
2
|
engines:
|
3
|
-
|
4
|
-
enabled: true
|
5
|
-
bundler-audit:
|
3
|
+
reek:
|
6
4
|
enabled: true
|
7
5
|
duplication:
|
8
6
|
enabled: true
|
@@ -11,13 +9,10 @@ engines:
|
|
11
9
|
- ruby
|
12
10
|
fixme:
|
13
11
|
enabled: true
|
14
|
-
reek:
|
15
|
-
enabled: true
|
16
12
|
rubocop:
|
17
13
|
enabled: true
|
18
14
|
ratings:
|
19
15
|
paths:
|
20
16
|
- "**.rb"
|
21
|
-
|
22
|
-
|
23
|
-
# - "*/spec/**/*"
|
17
|
+
exclude_paths:
|
18
|
+
- spec/
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,22 @@
|
|
1
|
+
## [v2.1.2] - 2016-12-22
|
2
|
+
- Fix loading `logfile` from shoryuken.yml
|
3
|
+
- [#296](https://github.com/phstc/shoryuken/pull/296)
|
4
|
+
|
5
|
+
- Add support for Strict priority polling (pending documentation)
|
6
|
+
- [#288](https://github.com/phstc/shoryuken/pull/288)
|
7
|
+
|
8
|
+
- Add `test_workers` for end-to-end testing supporting
|
9
|
+
- [#286](https://github.com/phstc/shoryuken/pull/286)
|
10
|
+
|
11
|
+
- Update README documenting `configure_client` and `configure_server`
|
12
|
+
- [#283](https://github.com/phstc/shoryuken/pull/283)
|
13
|
+
|
14
|
+
- Fix memory leak caused by async tracking busy threads
|
15
|
+
- [#289](https://github.com/phstc/shoryuken/pull/289)
|
16
|
+
|
17
|
+
- Refactor fetcher, polling strategy and manager
|
18
|
+
- [#284](https://github.com/phstc/shoryuken/pull/284)
|
19
|
+
|
1
20
|
## [v2.1.1] - 2016-12-05
|
2
21
|
- Fix aws deprecation warning message
|
3
22
|
- [#279](https://github.com/phstc/shoryuken/pull/279)
|
data/README.md
CHANGED
@@ -110,15 +110,6 @@ end
|
|
110
110
|
Sample configuration file `shoryuken.yml`.
|
111
111
|
|
112
112
|
```yaml
|
113
|
-
aws:
|
114
|
-
access_key_id: ... # or <%= ENV['AWS_ACCESS_KEY_ID'] %>
|
115
|
-
secret_access_key: ... # or <%= ENV['AWS_SECRET_ACCESS_KEY'] %>
|
116
|
-
region: us-east-1 # or <%= ENV['AWS_REGION'] %>
|
117
|
-
receive_message: # See http://docs.aws.amazon.com/sdkforruby/api/Aws/SQS/Client.html#receive_message-instance_method
|
118
|
-
# wait_time_seconds: N # The number of seconds to wait for new messages when polling. Defaults to the #wait_time_seconds defined on the queue
|
119
|
-
attribute_names:
|
120
|
-
- ApproximateReceiveCount
|
121
|
-
- SentTimestamp
|
122
113
|
concurrency: 25 # The number of allocated threads to process messages. Default 25
|
123
114
|
delay: 25 # The delay in seconds to pause a queue when it's empty. Default 0
|
124
115
|
queues:
|
@@ -127,24 +118,80 @@ queues:
|
|
127
118
|
- [low_priority, 1]
|
128
119
|
```
|
129
120
|
|
130
|
-
|
121
|
+
And setup ```aws``` options to use ```configure_client``` in `config/initializers/shoryuken.rb`:
|
131
122
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
123
|
+
```ruby
|
124
|
+
Shoryuken.configure_client do |config|
|
125
|
+
config.aws = {
|
126
|
+
secret_access_key: ..., # or ENV["AWS_SECRET_ACCESS_KEY"]
|
127
|
+
access_key_id: ..., # or ENV["AWS_ACCESS_KEY_ID"]
|
128
|
+
region: "us-east-1", # or ENV["AWS_REGION"]
|
129
|
+
receive_message: { # See http://docs.aws.amazon.com/sdkforruby/api/Aws/SQS/Client.html#receive_message-instance_method
|
130
|
+
# wait_time_seconds: N, # The number of seconds to wait for new messages when polling. Defaults to the #wait_time_seconds defined on the queue
|
131
|
+
attribute_names: [
|
132
|
+
"ApproximateReceiveCount",
|
133
|
+
"SentTimestamp"
|
134
|
+
]
|
135
|
+
}
|
136
|
+
}
|
137
|
+
end
|
138
|
+
```
|
139
|
+
|
140
|
+
If you use Shoryuken with plain ruby worker class (not Rails), please call `configure_client` at the beginning of the worker file:
|
141
|
+
|
142
|
+
```ruby
|
143
|
+
Shoryuken.configure_client do |config|
|
144
|
+
config.aws = {
|
145
|
+
secret_access_key: ENV["AWS_SECRET_ACCESS_KEY"],
|
146
|
+
access_key_id: ENV["AWS_ACCESS_KEY_ID"],
|
147
|
+
region: ENV["AWS_REGION"]
|
148
|
+
}
|
149
|
+
end
|
150
|
+
|
151
|
+
class MyWorker
|
152
|
+
end
|
153
|
+
```
|
136
154
|
|
137
|
-
The
|
155
|
+
The `aws` section is used to configure both the Aws objects used by Shoryuken internally, and also to set up some Shoryuken-specific config. The Shoryuken-specific keys are listed below, and you can expect any other key defined in that block to be passed on untouched to `Aws::SQS::Client#initialize`:
|
156
|
+
|
157
|
+
- `account_id` is used when generating SNS ARNs
|
158
|
+
- `sns_endpoint` can be used to explicitly override the SNS endpoint
|
159
|
+
- `sqs_endpoint` can be used to explicitly override the SQS endpoint
|
160
|
+
- `receive_message` can be used to define the options passed to the http://docs.aws.amazon.com/sdkforruby/api/Aws/SQS/Client.html#receive_message-instance_method
|
161
|
+
|
162
|
+
The `sns_endpoint` and `sqs_endpoint` Shoryuken-specific options will also fallback to the environment variables `AWS_SNS_ENDPOINT` and `AWS_SQS_ENDPOINT` respectively, if they are set.
|
138
163
|
|
139
164
|
### Configuration (producer side)
|
140
165
|
|
141
166
|
'Producer' processes need permissions to put messages into SQS. There are a few ways:
|
142
167
|
|
168
|
+
* Use the `configure_server` in Rails initializer
|
143
169
|
* Ensure the `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` env vars are set.
|
144
170
|
* Create a `~/.aws/credentials` file.
|
145
171
|
* Set `Aws.config[:credentials]` from Ruby code (e.g. in a Rails initializer)
|
146
172
|
* Use the Instance Profiles feature. The IAM role of the targeted machine must have an adequate SQS Policy.
|
147
173
|
|
174
|
+
For example, use the `configure_server` in `config/initializers/shoryuken.rb`:
|
175
|
+
|
176
|
+
```ruby
|
177
|
+
Shoryuken.configure_client do |config|
|
178
|
+
config.aws = {
|
179
|
+
secret_access_key: ENV["AWS_SECRET_ACCESS_KEY"],
|
180
|
+
access_key_id: ENV["AWS_ACCESS_KEY_ID"],
|
181
|
+
region: ENV["AWS_REGION"]
|
182
|
+
}
|
183
|
+
end
|
184
|
+
|
185
|
+
Shoryuken.configure_server do |config|
|
186
|
+
config.aws = {
|
187
|
+
secret_access_key: ENV["AWS_SECRET_ACCESS_KEY"],
|
188
|
+
access_key_id: ENV["AWS_ACCESS_KEY_ID"],
|
189
|
+
region: ENV["AWS_REGION"]
|
190
|
+
}
|
191
|
+
end
|
192
|
+
```
|
193
|
+
|
194
|
+
|
148
195
|
Note that storing your credentials into Amazon instances represents a security risk. Instance Profiles tends to be the best choice.
|
149
196
|
|
150
197
|
You can read about these in more detail [here](http://docs.aws.amazon.com/sdkforruby/api/Aws/SQS/Client.html).
|
data/lib/shoryuken.rb
CHANGED
@@ -21,6 +21,7 @@ require 'shoryuken/middleware/server/exponential_backoff_retry'
|
|
21
21
|
require 'shoryuken/middleware/server/timing'
|
22
22
|
require 'shoryuken/sns_arn'
|
23
23
|
require 'shoryuken/topic'
|
24
|
+
require 'shoryuken/polling'
|
24
25
|
|
25
26
|
module Shoryuken
|
26
27
|
DEFAULTS = {
|
@@ -33,7 +34,8 @@ module Shoryuken
|
|
33
34
|
startup: [],
|
34
35
|
quiet: [],
|
35
36
|
shutdown: [],
|
36
|
-
}
|
37
|
+
},
|
38
|
+
polling_strategy: Polling::WeightedRoundRobin,
|
37
39
|
}
|
38
40
|
|
39
41
|
@@queues = []
|
@@ -60,8 +60,8 @@ module Shoryuken
|
|
60
60
|
end
|
61
61
|
|
62
62
|
def initialize_logger
|
63
|
-
Shoryuken::Logging.initialize_logger(options[:logfile]) if options[:logfile]
|
64
|
-
Shoryuken.logger.level = Logger::DEBUG if options[:verbose]
|
63
|
+
Shoryuken::Logging.initialize_logger(Shoryuken.options[:logfile]) if Shoryuken.options[:logfile]
|
64
|
+
Shoryuken.logger.level = Logger::DEBUG if Shoryuken.options[:verbose]
|
65
65
|
end
|
66
66
|
|
67
67
|
def load_rails
|
data/lib/shoryuken/fetcher.rb
CHANGED
@@ -1,26 +1,9 @@
|
|
1
1
|
module Shoryuken
|
2
2
|
class Fetcher
|
3
|
-
include Celluloid
|
4
3
|
include Util
|
5
4
|
|
6
5
|
FETCH_LIMIT = 10
|
7
6
|
|
8
|
-
def initialize(manager)
|
9
|
-
@manager = manager
|
10
|
-
end
|
11
|
-
|
12
|
-
def receive_messages(queue, limit)
|
13
|
-
# AWS limits the batch size by 10
|
14
|
-
limit = limit > FETCH_LIMIT ? FETCH_LIMIT : limit
|
15
|
-
|
16
|
-
options = (Shoryuken::AwsConfig.options[:receive_message] || {}).dup
|
17
|
-
options[:max_number_of_messages] = limit
|
18
|
-
options[:message_attribute_names] = %w(All)
|
19
|
-
options[:attribute_names] = %w(All)
|
20
|
-
|
21
|
-
Shoryuken::Client.queues(queue).receive_messages options
|
22
|
-
end
|
23
|
-
|
24
7
|
def fetch(queue, available_processors)
|
25
8
|
watchdog('Fetcher#fetch died') do
|
26
9
|
started_at = Time.now
|
@@ -28,46 +11,34 @@ module Shoryuken
|
|
28
11
|
logger.debug { "Looking for new messages in '#{queue}'" }
|
29
12
|
|
30
13
|
begin
|
31
|
-
|
32
|
-
limit = batch ? FETCH_LIMIT : available_processors
|
33
|
-
|
34
|
-
if (sqs_msgs = Array(receive_messages(queue, limit))).any?
|
35
|
-
logger.debug { "Found #{sqs_msgs.size} messages for '#{queue}'" }
|
36
|
-
|
37
|
-
if batch
|
38
|
-
@manager.async.assign(queue, patch_sqs_msgs!(sqs_msgs))
|
39
|
-
else
|
40
|
-
sqs_msgs.each { |sqs_msg| @manager.async.assign(queue, sqs_msg) }
|
41
|
-
end
|
42
|
-
|
43
|
-
@manager.async.rebalance_queue_weight!(queue)
|
44
|
-
else
|
45
|
-
logger.debug { "No message found for '#{queue}'" }
|
46
|
-
|
47
|
-
@manager.async.pause_queue!(queue)
|
48
|
-
end
|
14
|
+
limit = available_processors > FETCH_LIMIT ? FETCH_LIMIT : available_processors
|
49
15
|
|
16
|
+
sqs_msgs = Array(receive_messages(queue, limit))
|
17
|
+
logger.info { "Found #{sqs_msgs.size} messages for '#{queue.name}'" }
|
50
18
|
logger.debug { "Fetcher for '#{queue}' completed in #{elapsed(started_at)} ms" }
|
19
|
+
sqs_msgs
|
51
20
|
rescue => ex
|
52
21
|
logger.error { "Error fetching message: #{ex}" }
|
53
22
|
logger.error { ex.backtrace.first }
|
23
|
+
[]
|
54
24
|
end
|
55
|
-
|
56
|
-
@manager.async.dispatch
|
57
25
|
end
|
58
|
-
|
59
26
|
end
|
60
27
|
|
61
28
|
private
|
62
29
|
|
63
|
-
def
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
30
|
+
def receive_messages(queue, limit)
|
31
|
+
# AWS limits the batch size by 10
|
32
|
+
limit = limit > FETCH_LIMIT ? FETCH_LIMIT : limit
|
33
|
+
|
34
|
+
options = (Shoryuken.options[:aws][:receive_message] || {}).dup
|
35
|
+
options[:max_number_of_messages] = limit
|
36
|
+
options[:message_attribute_names] = %w(All)
|
37
|
+
options[:attribute_names] = %w(All)
|
38
|
+
|
39
|
+
options.merge!(queue.options)
|
69
40
|
|
70
|
-
|
41
|
+
Shoryuken::Client.queues(queue.name).receive_messages(options)
|
71
42
|
end
|
72
43
|
end
|
73
44
|
end
|
data/lib/shoryuken/launcher.rb
CHANGED
@@ -10,17 +10,16 @@ module Shoryuken
|
|
10
10
|
def initialize
|
11
11
|
@condvar = Celluloid::Condition.new
|
12
12
|
@manager = Shoryuken::Manager.new_link(@condvar)
|
13
|
-
@fetcher = Shoryuken::Fetcher.new_link(manager)
|
14
13
|
|
15
14
|
@done = false
|
16
15
|
|
17
|
-
manager.fetcher =
|
16
|
+
manager.fetcher = Shoryuken::Fetcher.new
|
17
|
+
manager.polling_strategy = Shoryuken.options[:polling_strategy].new(Shoryuken.queues)
|
18
18
|
end
|
19
19
|
|
20
20
|
def stop(options = {})
|
21
21
|
watchdog('Launcher#stop') do
|
22
22
|
@done = true
|
23
|
-
@fetcher.terminate if @fetcher.alive?
|
24
23
|
|
25
24
|
manager.async.stop(shutdown: !!options[:shutdown], timeout: Shoryuken.options[:timeout])
|
26
25
|
@condvar.wait
|
data/lib/shoryuken/manager.rb
CHANGED
@@ -7,9 +7,14 @@ module Shoryuken
|
|
7
7
|
include Util
|
8
8
|
|
9
9
|
attr_accessor :fetcher
|
10
|
+
attr_accessor :polling_strategy
|
11
|
+
|
12
|
+
exclusive :dispatch
|
10
13
|
|
11
14
|
trap_exit :processor_died
|
12
15
|
|
16
|
+
BATCH_LIMIT = 10
|
17
|
+
|
13
18
|
def initialize(condvar)
|
14
19
|
@count = Shoryuken.options[:concurrency] || 25
|
15
20
|
raise(ArgumentError, "Concurrency value #{@count} is invalid, it needs to be a positive number") unless @count > 0
|
@@ -18,9 +23,9 @@ module Shoryuken
|
|
18
23
|
|
19
24
|
@done = false
|
20
25
|
|
21
|
-
@
|
22
|
-
@
|
23
|
-
@
|
26
|
+
@busy_processors = []
|
27
|
+
@busy_threads = {}
|
28
|
+
@ready_processors = @count.times.map { build_processor }
|
24
29
|
end
|
25
30
|
|
26
31
|
def start
|
@@ -40,16 +45,14 @@ module Shoryuken
|
|
40
45
|
|
41
46
|
fire_event(:shutdown, true)
|
42
47
|
|
43
|
-
|
48
|
+
logger.info { "Shutting down #{@ready_processors.size} quiet workers" }
|
44
49
|
|
45
|
-
|
46
|
-
|
47
|
-
@ready.each do |processor|
|
50
|
+
@ready_processors.each do |processor|
|
48
51
|
processor.terminate if processor.alive?
|
49
52
|
end
|
50
|
-
@
|
53
|
+
@ready_processors.clear
|
51
54
|
|
52
|
-
return after(0) { @finished.signal } if @
|
55
|
+
return after(0) { @finished.signal } if @busy_processors.empty?
|
53
56
|
|
54
57
|
if options[:shutdown]
|
55
58
|
hard_shutdown_in(options[:timeout])
|
@@ -63,14 +66,15 @@ module Shoryuken
|
|
63
66
|
watchdog('Manager#processor_done died') do
|
64
67
|
logger.debug { "Process done for '#{queue}'" }
|
65
68
|
|
66
|
-
@
|
67
|
-
@
|
69
|
+
@busy_processors.delete(processor)
|
70
|
+
@busy_threads.delete(processor.object_id)
|
68
71
|
|
69
72
|
if stopped?
|
70
73
|
processor.terminate if processor.alive?
|
71
|
-
return after(0) { @finished.signal } if @
|
74
|
+
return after(0) { @finished.signal } if @busy_processors.empty?
|
72
75
|
else
|
73
|
-
@
|
76
|
+
@ready_processors << processor
|
77
|
+
async.dispatch
|
74
78
|
end
|
75
79
|
end
|
76
80
|
end
|
@@ -79,13 +83,14 @@ module Shoryuken
|
|
79
83
|
watchdog("Manager#processor_died died") do
|
80
84
|
logger.error { "Process died, reason: #{reason}" }
|
81
85
|
|
82
|
-
@
|
83
|
-
@
|
86
|
+
@busy_processors.delete(processor)
|
87
|
+
@busy_threads.delete(processor.object_id)
|
84
88
|
|
85
89
|
if stopped?
|
86
|
-
return after(0) { @finished.signal } if @
|
90
|
+
return after(0) { @finished.signal } if @busy_processors.empty?
|
87
91
|
else
|
88
|
-
@
|
92
|
+
@ready_processors << build_processor
|
93
|
+
async.dispatch
|
89
94
|
end
|
90
95
|
end
|
91
96
|
end
|
@@ -94,61 +99,27 @@ module Shoryuken
|
|
94
99
|
@done
|
95
100
|
end
|
96
101
|
|
97
|
-
def assign(queue, sqs_msg)
|
98
|
-
watchdog('Manager#assign died') do
|
99
|
-
logger.debug { "Assigning #{sqs_msg.message_id}" }
|
100
|
-
|
101
|
-
processor = @ready.pop
|
102
|
-
@busy << processor
|
103
|
-
|
104
|
-
processor.async.process(queue, sqs_msg)
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
def rebalance_queue_weight!(queue)
|
109
|
-
watchdog('Manager#rebalance_queue_weight! died') do
|
110
|
-
if (original = original_queue_weight(queue)) > (current = current_queue_weight(queue))
|
111
|
-
logger.info { "Increasing '#{queue}' weight to #{current + 1}, max: #{original}" }
|
112
|
-
|
113
|
-
@queues << queue
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
def pause_queue!(queue)
|
119
|
-
return if !@queues.include?(queue) || Shoryuken.options[:delay].to_f <= 0
|
120
|
-
|
121
|
-
logger.debug { "Pausing '#{queue}' for #{Shoryuken.options[:delay].to_f} seconds, because it's empty" }
|
122
|
-
|
123
|
-
@queues.delete(queue)
|
124
|
-
|
125
|
-
after(Shoryuken.options[:delay].to_f) { async.restart_queue!(queue) }
|
126
|
-
end
|
127
|
-
|
128
|
-
|
129
102
|
def dispatch
|
130
103
|
return if stopped?
|
131
104
|
|
132
|
-
logger.debug { "Ready: #{@
|
105
|
+
logger.debug { "Ready: #{@ready_processors.size}, Busy: #{@busy_processors.size}, Active Queues: #{polling_strategy.active_queues}" }
|
133
106
|
|
134
|
-
if @
|
107
|
+
if @ready_processors.empty?
|
135
108
|
logger.debug { 'Pausing fetcher, because all processors are busy' }
|
136
|
-
|
137
109
|
dispatch_later
|
138
110
|
return
|
139
111
|
end
|
140
112
|
|
141
|
-
|
142
|
-
|
143
|
-
else
|
113
|
+
queue = polling_strategy.next_queue
|
114
|
+
if queue.nil?
|
144
115
|
logger.debug { 'Pausing fetcher, because all queues are paused' }
|
145
|
-
|
146
|
-
|
116
|
+
dispatch_later
|
117
|
+
return
|
147
118
|
end
|
148
|
-
end
|
149
119
|
|
150
|
-
|
151
|
-
|
120
|
+
batched_queue?(queue) ? dispatch_batch(queue) : dispatch_single_messages(queue)
|
121
|
+
|
122
|
+
async.dispatch
|
152
123
|
end
|
153
124
|
|
154
125
|
private
|
@@ -160,67 +131,48 @@ module Shoryuken
|
|
160
131
|
end
|
161
132
|
end
|
162
133
|
|
163
|
-
def
|
164
|
-
|
165
|
-
|
166
|
-
processor
|
167
|
-
end
|
168
|
-
|
169
|
-
def restart_queue!(queue)
|
170
|
-
return if stopped?
|
171
|
-
|
172
|
-
unless @queues.include? queue
|
173
|
-
logger.debug { "Restarting '#{queue}'" }
|
174
|
-
|
175
|
-
@queues << queue
|
176
|
-
|
177
|
-
if @fetcher_paused
|
178
|
-
logger.debug { 'Restarting fetcher' }
|
134
|
+
def assign(queue, sqs_msg)
|
135
|
+
watchdog('Manager#assign died') do
|
136
|
+
logger.debug { "Assigning #{sqs_msg.message_id}" }
|
179
137
|
|
180
|
-
|
138
|
+
processor = @ready_processors.pop
|
139
|
+
@busy_threads[processor.object_id] = processor.running_thread
|
140
|
+
@busy_processors << processor
|
181
141
|
|
182
|
-
|
183
|
-
end
|
142
|
+
processor.async.process(queue, sqs_msg)
|
184
143
|
end
|
185
144
|
end
|
186
145
|
|
187
|
-
def
|
188
|
-
|
146
|
+
def dispatch_batch(queue)
|
147
|
+
batch = fetcher.fetch(queue, BATCH_LIMIT)
|
148
|
+
polling_strategy.messages_found(queue.name, batch.size)
|
149
|
+
assign(queue.name, patch_batch!(batch))
|
189
150
|
end
|
190
151
|
|
191
|
-
def
|
192
|
-
|
152
|
+
def dispatch_single_messages(queue)
|
153
|
+
messages = fetcher.fetch(queue, @ready_processors.size)
|
154
|
+
polling_strategy.messages_found(queue.name, messages.size)
|
155
|
+
messages.each { |message| assign(queue.name, message) }
|
193
156
|
end
|
194
157
|
|
195
|
-
def
|
196
|
-
|
158
|
+
def batched_queue?(queue)
|
159
|
+
Shoryuken.worker_registry.batch_receive_messages?(queue.name)
|
197
160
|
end
|
198
161
|
|
199
|
-
def
|
200
|
-
|
201
|
-
|
202
|
-
# get/remove the first queue in the list
|
203
|
-
queue = @queues.shift
|
204
|
-
|
205
|
-
unless defined?(::ActiveJob) || !Shoryuken.worker_registry.workers(queue).empty?
|
206
|
-
# when no worker registered pause the queue to avoid endless recursion
|
207
|
-
logger.debug { "Pausing '#{queue}' for #{Shoryuken.options[:delay].to_f} seconds, because no workers registered" }
|
208
|
-
|
209
|
-
after(Shoryuken.options[:delay].to_f) { async.restart_queue!(queue) }
|
210
|
-
|
211
|
-
return next_queue
|
212
|
-
end
|
213
|
-
|
214
|
-
# add queue back to the end of the list
|
215
|
-
@queues << queue
|
162
|
+
def delay
|
163
|
+
Shoryuken.options[:delay].to_f
|
164
|
+
end
|
216
165
|
|
217
|
-
|
166
|
+
def build_processor
|
167
|
+
processor = Processor.new_link(current_actor)
|
168
|
+
processor.proxy_id = processor.object_id
|
169
|
+
processor
|
218
170
|
end
|
219
171
|
|
220
172
|
def soft_shutdown(delay)
|
221
|
-
logger.info { "Waiting for #{@
|
173
|
+
logger.info { "Waiting for #{@busy_processors.size} busy workers" }
|
222
174
|
|
223
|
-
if @
|
175
|
+
if @busy_processors.size > 0
|
224
176
|
after(delay) { soft_shutdown(delay) }
|
225
177
|
else
|
226
178
|
@finished.signal
|
@@ -228,16 +180,16 @@ module Shoryuken
|
|
228
180
|
end
|
229
181
|
|
230
182
|
def hard_shutdown_in(delay)
|
231
|
-
logger.info { "Waiting for #{@
|
183
|
+
logger.info { "Waiting for #{@busy_processors.size} busy workers" }
|
232
184
|
logger.info { "Pausing up to #{delay} seconds to allow workers to finish..." }
|
233
185
|
|
234
186
|
after(delay) do
|
235
187
|
watchdog('Manager#hard_shutdown_in died') do
|
236
|
-
if @
|
237
|
-
logger.info { "Hard shutting down #{@
|
188
|
+
if @busy_processors.size > 0
|
189
|
+
logger.info { "Hard shutting down #{@busy_processors.size} busy workers" }
|
238
190
|
|
239
|
-
@
|
240
|
-
if processor.alive? && t = @
|
191
|
+
@busy_processors.each do |processor|
|
192
|
+
if processor.alive? && t = @busy_threads.delete(processor.object_id)
|
241
193
|
t.raise Shutdown
|
242
194
|
end
|
243
195
|
end
|
@@ -247,5 +199,15 @@ module Shoryuken
|
|
247
199
|
end
|
248
200
|
end
|
249
201
|
end
|
202
|
+
|
203
|
+
def patch_batch!(sqs_msgs)
|
204
|
+
sqs_msgs.instance_eval do
|
205
|
+
def message_id
|
206
|
+
"batch-with-#{size}-messages"
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
sqs_msgs
|
211
|
+
end
|
250
212
|
end
|
251
213
|
end
|