shoryuken 2.1.1 → 2.1.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|