shoryuken 5.0.5 → 6.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.devcontainer/Dockerfile +17 -0
- data/.devcontainer/base.Dockerfile +43 -0
- data/.devcontainer/devcontainer.json +35 -0
- data/.github/dependabot.yml +6 -0
- data/.github/workflows/specs.yml +65 -0
- data/.github/workflows/stale.yml +20 -0
- data/.gitignore +1 -1
- data/.reek.yml +5 -0
- data/.rubocop.yml +1 -1
- data/Appraisals +42 -0
- data/CHANGELOG.md +114 -0
- data/Gemfile +8 -3
- data/README.md +41 -1
- data/Rakefile +15 -1
- data/bin/cli/sqs.rb +51 -6
- data/gemfiles/.gitignore +1 -0
- data/gemfiles/aws_sdk_core_2.gemfile +21 -0
- data/gemfiles/rails_4_2.gemfile +20 -0
- data/gemfiles/rails_5_2.gemfile +21 -0
- data/gemfiles/rails_6_0.gemfile +21 -0
- data/gemfiles/rails_6_1.gemfile +21 -0
- data/gemfiles/rails_7_0.gemfile +22 -0
- data/lib/shoryuken/default_exception_handler.rb +10 -0
- data/lib/shoryuken/environment_loader.rb +22 -4
- data/lib/shoryuken/extensions/active_job_adapter.rb +30 -20
- data/lib/shoryuken/extensions/active_job_extensions.rb +38 -0
- data/lib/shoryuken/launcher.rb +26 -3
- data/lib/shoryuken/logging.rb +2 -2
- data/lib/shoryuken/manager.rb +50 -14
- data/lib/shoryuken/message.rb +11 -28
- data/lib/shoryuken/options.rb +6 -3
- data/lib/shoryuken/polling/base.rb +2 -0
- data/lib/shoryuken/polling/strict_priority.rb +8 -0
- data/lib/shoryuken/polling/weighted_round_robin.rb +9 -0
- data/lib/shoryuken/processor.rb +1 -2
- data/lib/shoryuken/queue.rb +5 -3
- data/lib/shoryuken/runner.rb +4 -3
- data/lib/shoryuken/version.rb +1 -1
- data/lib/shoryuken.rb +8 -0
- data/shoryuken.gemspec +1 -2
- data/spec/integration/launcher_spec.rb +29 -2
- data/spec/shared_examples_for_active_job.rb +230 -11
- data/spec/shoryuken/default_exception_handler_spec.rb +71 -0
- data/spec/shoryuken/environment_loader_spec.rb +62 -9
- data/spec/shoryuken/extensions/active_job_adapter_spec.rb +1 -1
- data/spec/shoryuken/extensions/active_job_base_spec.rb +84 -0
- data/spec/shoryuken/extensions/active_job_concurrent_send_adapter_spec.rb +4 -0
- data/spec/shoryuken/extensions/active_job_wrapper_spec.rb +20 -0
- data/spec/shoryuken/fetcher_spec.rb +12 -12
- data/spec/shoryuken/launcher_spec.rb +105 -0
- data/spec/shoryuken/manager_spec.rb +61 -1
- data/spec/shoryuken/polling/strict_priority_spec.rb +10 -0
- data/spec/shoryuken/polling/weighted_round_robin_spec.rb +35 -0
- data/spec/shoryuken/queue_spec.rb +10 -5
- data/spec/shoryuken/worker/default_executor_spec.rb +48 -48
- data/spec/shoryuken_spec.rb +9 -0
- data/spec/spec_helper.rb +7 -9
- metadata +32 -24
- data/.travis.yml +0 -30
- data/Gemfile.aws-sdk-core-v2 +0 -13
@@ -0,0 +1,21 @@
|
|
1
|
+
# This file was generated by Appraisal
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
group :test do
|
6
|
+
gem "activejob", "~> 6.0"
|
7
|
+
gem "aws-sdk-core", "~> 3"
|
8
|
+
gem "aws-sdk-sqs"
|
9
|
+
gem "codeclimate-test-reporter", require: nil
|
10
|
+
gem "httparty"
|
11
|
+
gem "multi_xml"
|
12
|
+
gem "simplecov"
|
13
|
+
end
|
14
|
+
|
15
|
+
group :development do
|
16
|
+
gem "appraisal", git: "https://github.com/thoughtbot/appraisal.git"
|
17
|
+
gem "pry-byebug", "3.9.0"
|
18
|
+
gem "rubocop"
|
19
|
+
end
|
20
|
+
|
21
|
+
gemspec path: "../"
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# This file was generated by Appraisal
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
group :test do
|
6
|
+
gem "activejob", "~> 6.1"
|
7
|
+
gem "aws-sdk-core", "~> 3"
|
8
|
+
gem "aws-sdk-sqs"
|
9
|
+
gem "codeclimate-test-reporter", require: nil
|
10
|
+
gem "httparty"
|
11
|
+
gem "multi_xml"
|
12
|
+
gem "simplecov"
|
13
|
+
end
|
14
|
+
|
15
|
+
group :development do
|
16
|
+
gem "appraisal", git: "https://github.com/thoughtbot/appraisal.git"
|
17
|
+
gem "pry-byebug", "3.9.0"
|
18
|
+
gem "rubocop"
|
19
|
+
end
|
20
|
+
|
21
|
+
gemspec path: "../"
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# This file was generated by Appraisal
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
group :test do
|
6
|
+
gem "activejob", "~> 7.0"
|
7
|
+
gem "aws-sdk-core", "~> 3"
|
8
|
+
gem "aws-sdk-sqs"
|
9
|
+
gem "codeclimate-test-reporter", require: nil
|
10
|
+
gem "httparty"
|
11
|
+
gem "multi_xml"
|
12
|
+
gem "simplecov"
|
13
|
+
end
|
14
|
+
|
15
|
+
group :development do
|
16
|
+
gem "appraisal", git: "https://github.com/thoughtbot/appraisal.git"
|
17
|
+
gem "rubocop"
|
18
|
+
gem "pry", ">= 0.14.2"
|
19
|
+
gem "pry-byebug", ">= 3.10.1"
|
20
|
+
end
|
21
|
+
|
22
|
+
gemspec path: "../"
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Shoryuken
|
2
|
+
class DefaultExceptionHandler
|
3
|
+
extend Util
|
4
|
+
|
5
|
+
def self.call(exception, _queue, _sqs_msg)
|
6
|
+
logger.error { "Processor failed: #{exception.message}" }
|
7
|
+
logger.error { exception.backtrace.join("\n") } if exception.backtrace
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -18,12 +18,12 @@ module Shoryuken
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def setup_options
|
21
|
+
initialize_rails if load_rails?
|
21
22
|
initialize_options
|
22
23
|
initialize_logger
|
23
24
|
end
|
24
25
|
|
25
26
|
def load
|
26
|
-
load_rails if Shoryuken.options[:rails]
|
27
27
|
prefix_active_job_queue_names
|
28
28
|
parse_queues
|
29
29
|
require_workers
|
@@ -55,7 +55,7 @@ module Shoryuken
|
|
55
55
|
Shoryuken.logger.level = Logger::DEBUG if Shoryuken.options[:verbose]
|
56
56
|
end
|
57
57
|
|
58
|
-
def
|
58
|
+
def initialize_rails
|
59
59
|
# Adapted from: https://github.com/mperham/sidekiq/blob/master/lib/sidekiq/cli.rb
|
60
60
|
|
61
61
|
require 'rails'
|
@@ -70,12 +70,22 @@ module Shoryuken
|
|
70
70
|
::Rails.application.config.eager_load = true
|
71
71
|
end
|
72
72
|
end
|
73
|
-
|
73
|
+
if Shoryuken.active_job?
|
74
|
+
require 'shoryuken/extensions/active_job_extensions'
|
75
|
+
require 'shoryuken/extensions/active_job_adapter'
|
76
|
+
require 'shoryuken/extensions/active_job_concurrent_send_adapter'
|
77
|
+
end
|
74
78
|
require File.expand_path('config/environment.rb')
|
75
79
|
end
|
76
80
|
end
|
77
81
|
|
82
|
+
def load_rails?
|
83
|
+
options[:rails]
|
84
|
+
end
|
85
|
+
|
78
86
|
def prefix_active_job_queue_name(queue_name, weight)
|
87
|
+
return [queue_name, weight] if queue_name.start_with?('https://', 'arn:')
|
88
|
+
|
79
89
|
queue_name_prefix = ::ActiveJob::Base.queue_name_prefix
|
80
90
|
queue_name_delimiter = ::ActiveJob::Base.queue_name_delimiter
|
81
91
|
|
@@ -153,9 +163,17 @@ module Shoryuken
|
|
153
163
|
|
154
164
|
return if non_existent_queues.none?
|
155
165
|
|
166
|
+
# NOTE: HEREDOC's ~ operator removes indents, but is only available Ruby 2.3+
|
167
|
+
# See github PR: https://github.com/ruby-shoryuken/shoryuken/pull/691#issuecomment-1007653595
|
168
|
+
error_msg = <<-MSG.gsub(/^\s+/, '')
|
169
|
+
The specified queue(s) #{non_existent_queues.join(', ')} do not exist.
|
170
|
+
Try 'shoryuken sqs create QUEUE-NAME' for creating a queue with default settings.
|
171
|
+
It's also possible that you don't have permission to access the specified queues.
|
172
|
+
MSG
|
173
|
+
|
156
174
|
fail(
|
157
175
|
ArgumentError,
|
158
|
-
|
176
|
+
error_msg
|
159
177
|
)
|
160
178
|
end
|
161
179
|
|
@@ -33,8 +33,12 @@ module ActiveJob
|
|
33
33
|
def enqueue(job, options = {}) #:nodoc:
|
34
34
|
register_worker!(job)
|
35
35
|
|
36
|
+
job.sqs_send_message_parameters.merge! options
|
37
|
+
|
36
38
|
queue = Shoryuken::Client.queues(job.queue_name)
|
37
|
-
|
39
|
+
send_message_params = message queue, job
|
40
|
+
job.sqs_send_message_parameters = send_message_params
|
41
|
+
queue.send_message send_message_params
|
38
42
|
end
|
39
43
|
|
40
44
|
def enqueue_at(job, timestamp) #:nodoc:
|
@@ -50,44 +54,50 @@ module ActiveJob
|
|
50
54
|
delay
|
51
55
|
end
|
52
56
|
|
53
|
-
def message(queue, job
|
57
|
+
def message(queue, job)
|
54
58
|
body = job.serialize
|
59
|
+
job_params = job.sqs_send_message_parameters
|
60
|
+
|
61
|
+
attributes = job_params[:message_attributes] || {}
|
55
62
|
|
56
|
-
msg = {
|
63
|
+
msg = {
|
64
|
+
message_body: body,
|
65
|
+
message_attributes: attributes.merge(MESSAGE_ATTRIBUTES)
|
66
|
+
}
|
57
67
|
|
58
68
|
if queue.fifo?
|
59
|
-
# See https://github.com/
|
60
|
-
|
69
|
+
# See https://github.com/ruby-shoryuken/shoryuken/issues/457 and
|
70
|
+
# https://github.com/ruby-shoryuken/shoryuken/pull/750#issuecomment-1781317929
|
71
|
+
msg[:message_deduplication_id] = Digest::SHA256.hexdigest(
|
72
|
+
JSON.dump(body.except('job_id', 'enqueued_at'))
|
73
|
+
)
|
61
74
|
end
|
62
75
|
|
63
|
-
msg
|
64
|
-
msg[:message_attributes] = message_attributes
|
65
|
-
|
66
|
-
msg.merge(options)
|
76
|
+
msg.merge(job_params.except(:message_attributes))
|
67
77
|
end
|
68
78
|
|
69
79
|
def register_worker!(job)
|
70
80
|
Shoryuken.register_worker(job.queue_name, JobWrapper)
|
71
81
|
end
|
72
82
|
|
73
|
-
def message_attributes
|
74
|
-
@message_attributes ||= {
|
75
|
-
'shoryuken_class' => {
|
76
|
-
string_value: JobWrapper.to_s,
|
77
|
-
data_type: 'String'
|
78
|
-
}
|
79
|
-
}
|
80
|
-
end
|
81
|
-
|
82
83
|
class JobWrapper #:nodoc:
|
83
84
|
include Shoryuken::Worker
|
84
85
|
|
85
86
|
shoryuken_options body_parser: :json, auto_delete: true
|
86
87
|
|
87
|
-
def perform(
|
88
|
-
|
88
|
+
def perform(sqs_msg, hash)
|
89
|
+
receive_count = sqs_msg.attributes['ApproximateReceiveCount'].to_i
|
90
|
+
past_receives = receive_count - 1
|
91
|
+
Base.execute hash.merge({ 'executions' => past_receives })
|
89
92
|
end
|
90
93
|
end
|
94
|
+
|
95
|
+
MESSAGE_ATTRIBUTES = {
|
96
|
+
'shoryuken_class' => {
|
97
|
+
string_value: JobWrapper.to_s,
|
98
|
+
data_type: 'String'
|
99
|
+
}
|
100
|
+
}.freeze
|
91
101
|
end
|
92
102
|
end
|
93
103
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Shoryuken
|
2
|
+
module ActiveJobExtensions
|
3
|
+
# Adds an accessor for SQS SendMessage parameters on ActiveJob jobs
|
4
|
+
# (instances of ActiveJob::Base). Shoryuken ActiveJob queue adapters use
|
5
|
+
# these parameters when enqueueing jobs; other adapters can ignore them.
|
6
|
+
module SQSSendMessageParametersAccessor
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
attr_accessor :sqs_send_message_parameters
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Initializes SQS SendMessage parameters on instances of ActiveJob::Base
|
15
|
+
# to the empty hash, and populates it whenever `#enqueue` is called, such
|
16
|
+
# as when using ActiveJob::Base.set.
|
17
|
+
module SQSSendMessageParametersSupport
|
18
|
+
def initialize(*arguments)
|
19
|
+
super(*arguments)
|
20
|
+
self.sqs_send_message_parameters = {}
|
21
|
+
end
|
22
|
+
ruby2_keywords(:initialize) if respond_to?(:ruby2_keywords, true)
|
23
|
+
|
24
|
+
def enqueue(options = {})
|
25
|
+
sqs_options = options.extract! :message_attributes,
|
26
|
+
:message_system_attributes,
|
27
|
+
:message_deduplication_id,
|
28
|
+
:message_group_id
|
29
|
+
sqs_send_message_parameters.merge! sqs_options
|
30
|
+
|
31
|
+
super
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
ActiveJob::Base.include Shoryuken::ActiveJobExtensions::SQSSendMessageParametersAccessor
|
38
|
+
ActiveJob::Base.prepend Shoryuken::ActiveJobExtensions::SQSSendMessageParametersSupport
|
data/lib/shoryuken/launcher.rb
CHANGED
@@ -16,11 +16,13 @@ module Shoryuken
|
|
16
16
|
def stop!
|
17
17
|
initiate_stop
|
18
18
|
|
19
|
-
|
19
|
+
# Don't await here so the timeout below is not delayed
|
20
|
+
stop_new_dispatching
|
20
21
|
|
21
|
-
|
22
|
+
executor.shutdown
|
23
|
+
executor.kill unless executor.wait_for_termination(Shoryuken.options[:timeout])
|
22
24
|
|
23
|
-
|
25
|
+
fire_event(:stopped)
|
24
26
|
end
|
25
27
|
|
26
28
|
def stop
|
@@ -28,12 +30,32 @@ module Shoryuken
|
|
28
30
|
|
29
31
|
initiate_stop
|
30
32
|
|
33
|
+
stop_new_dispatching
|
34
|
+
await_dispatching_in_progress
|
35
|
+
|
31
36
|
executor.shutdown
|
32
37
|
executor.wait_for_termination
|
38
|
+
|
39
|
+
fire_event(:stopped)
|
40
|
+
end
|
41
|
+
|
42
|
+
def healthy?
|
43
|
+
Shoryuken.groups.keys.all? do |group|
|
44
|
+
manager = @managers.find { |m| m.group == group }
|
45
|
+
manager && manager.running?
|
46
|
+
end
|
33
47
|
end
|
34
48
|
|
35
49
|
private
|
36
50
|
|
51
|
+
def stop_new_dispatching
|
52
|
+
@managers.each(&:stop_new_dispatching)
|
53
|
+
end
|
54
|
+
|
55
|
+
def await_dispatching_in_progress
|
56
|
+
@managers.each(&:await_dispatching_in_progress)
|
57
|
+
end
|
58
|
+
|
37
59
|
def executor
|
38
60
|
@_executor ||= Shoryuken.launcher_executor || Concurrent.global_io_executor
|
39
61
|
end
|
@@ -71,6 +93,7 @@ module Shoryuken
|
|
71
93
|
def create_managers
|
72
94
|
Shoryuken.groups.map do |group, options|
|
73
95
|
Shoryuken::Manager.new(
|
96
|
+
group,
|
74
97
|
Shoryuken::Fetcher.new(group),
|
75
98
|
Shoryuken.polling_strategy(group).new(options[:queues], Shoryuken.delay(group)),
|
76
99
|
options[:concurrency],
|
data/lib/shoryuken/logging.rb
CHANGED
@@ -30,11 +30,11 @@ module Shoryuken
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def self.logger
|
33
|
-
@logger
|
33
|
+
@logger ||= initialize_logger
|
34
34
|
end
|
35
35
|
|
36
36
|
def self.logger=(log)
|
37
|
-
@logger = (log
|
37
|
+
@logger = (log || Logger.new('/dev/null'))
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
data/lib/shoryuken/manager.rb
CHANGED
@@ -6,27 +6,47 @@ module Shoryuken
|
|
6
6
|
# See https://github.com/phstc/shoryuken/issues/348#issuecomment-292847028
|
7
7
|
MIN_DISPATCH_INTERVAL = 0.1
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
@
|
13
|
-
@
|
14
|
-
@
|
15
|
-
@
|
9
|
+
attr_reader :group
|
10
|
+
|
11
|
+
def initialize(group, fetcher, polling_strategy, concurrency, executor)
|
12
|
+
@group = group
|
13
|
+
@fetcher = fetcher
|
14
|
+
@polling_strategy = polling_strategy
|
15
|
+
@max_processors = concurrency
|
16
|
+
@busy_processors = Concurrent::AtomicFixnum.new(0)
|
17
|
+
@executor = executor
|
18
|
+
@running = Concurrent::AtomicBoolean.new(true)
|
19
|
+
@stop_new_dispatching = Concurrent::AtomicBoolean.new(false)
|
20
|
+
@dispatching_release_signal = ::Queue.new
|
16
21
|
end
|
17
22
|
|
18
23
|
def start
|
24
|
+
fire_utilization_update_event
|
19
25
|
dispatch_loop
|
20
26
|
end
|
21
27
|
|
22
|
-
|
28
|
+
def stop_new_dispatching
|
29
|
+
@stop_new_dispatching.make_true
|
30
|
+
end
|
31
|
+
|
32
|
+
def await_dispatching_in_progress
|
33
|
+
# There might still be a dispatching on-going, as the response from SQS could take some time
|
34
|
+
# We don't want to stop the process before processing incoming messages, as they would stay "in-flight" for some time on SQS
|
35
|
+
# We use a queue, as the dispatch_loop is running on another thread, and this is a efficient way of communicating between threads.
|
36
|
+
@dispatching_release_signal.pop
|
37
|
+
end
|
23
38
|
|
24
39
|
def running?
|
25
40
|
@running.true? && @executor.running?
|
26
41
|
end
|
27
42
|
|
43
|
+
private
|
44
|
+
|
28
45
|
def dispatch_loop
|
29
|
-
|
46
|
+
if @stop_new_dispatching.true? || !running?
|
47
|
+
@dispatching_release_signal << 1
|
48
|
+
return
|
49
|
+
end
|
30
50
|
|
31
51
|
@executor.post { dispatch }
|
32
52
|
end
|
@@ -57,8 +77,15 @@ module Shoryuken
|
|
57
77
|
@max_processors - busy
|
58
78
|
end
|
59
79
|
|
60
|
-
def processor_done
|
80
|
+
def processor_done(queue)
|
61
81
|
@busy_processors.decrement
|
82
|
+
fire_utilization_update_event
|
83
|
+
|
84
|
+
client_queue = Shoryuken::Client.queues(queue)
|
85
|
+
return unless client_queue.fifo?
|
86
|
+
return unless @polling_strategy.respond_to?(:message_processed)
|
87
|
+
|
88
|
+
@polling_strategy.message_processed(queue)
|
62
89
|
end
|
63
90
|
|
64
91
|
def assign(queue_name, sqs_msg)
|
@@ -67,10 +94,12 @@ module Shoryuken
|
|
67
94
|
logger.debug { "Assigning #{sqs_msg.message_id}" }
|
68
95
|
|
69
96
|
@busy_processors.increment
|
97
|
+
fire_utilization_update_event
|
70
98
|
|
71
|
-
Concurrent::Promise
|
72
|
-
executor: @executor
|
73
|
-
|
99
|
+
Concurrent::Promise
|
100
|
+
.execute(executor: @executor) { Processor.process(queue_name, sqs_msg) }
|
101
|
+
.then { processor_done(queue_name) }
|
102
|
+
.rescue { processor_done(queue_name) }
|
74
103
|
end
|
75
104
|
|
76
105
|
def dispatch_batch(queue)
|
@@ -81,7 +110,6 @@ module Shoryuken
|
|
81
110
|
|
82
111
|
def dispatch_single_messages(queue)
|
83
112
|
messages = @fetcher.fetch(queue, ready)
|
84
|
-
|
85
113
|
@polling_strategy.messages_found(queue.name, messages.size)
|
86
114
|
messages.each { |message| assign(queue.name, message) }
|
87
115
|
end
|
@@ -108,5 +136,13 @@ module Shoryuken
|
|
108
136
|
|
109
137
|
@running.make_false
|
110
138
|
end
|
139
|
+
|
140
|
+
def fire_utilization_update_event
|
141
|
+
fire_event :utilization_update, false, {
|
142
|
+
group: @group,
|
143
|
+
max_processors: @max_processors,
|
144
|
+
busy_processors: busy
|
145
|
+
}
|
146
|
+
end
|
111
147
|
end
|
112
148
|
end
|
data/lib/shoryuken/message.rb
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
module Shoryuken
|
2
2
|
class Message
|
3
|
+
extend Forwardable
|
4
|
+
|
5
|
+
def_delegators(:data,
|
6
|
+
:message_id,
|
7
|
+
:receipt_handle,
|
8
|
+
:md5_of_body,
|
9
|
+
:body,
|
10
|
+
:attributes,
|
11
|
+
:md5_of_message_attributes,
|
12
|
+
:message_attributes)
|
13
|
+
|
3
14
|
attr_accessor :client, :queue_url, :queue_name, :data
|
4
15
|
|
5
16
|
def initialize(client, queue, data)
|
@@ -29,33 +40,5 @@ module Shoryuken
|
|
29
40
|
visibility_timeout: timeout
|
30
41
|
)
|
31
42
|
end
|
32
|
-
|
33
|
-
def message_id
|
34
|
-
data.message_id
|
35
|
-
end
|
36
|
-
|
37
|
-
def receipt_handle
|
38
|
-
data.receipt_handle
|
39
|
-
end
|
40
|
-
|
41
|
-
def md5_of_body
|
42
|
-
data.md5_of_body
|
43
|
-
end
|
44
|
-
|
45
|
-
def body
|
46
|
-
data.body
|
47
|
-
end
|
48
|
-
|
49
|
-
def attributes
|
50
|
-
data.attributes
|
51
|
-
end
|
52
|
-
|
53
|
-
def md5_of_message_attributes
|
54
|
-
data.md5_of_message_attributes
|
55
|
-
end
|
56
|
-
|
57
|
-
def message_attributes
|
58
|
-
data.message_attributes
|
59
|
-
end
|
60
43
|
end
|
61
44
|
end
|
data/lib/shoryuken/options.rb
CHANGED
@@ -9,20 +9,23 @@ module Shoryuken
|
|
9
9
|
lifecycle_events: {
|
10
10
|
startup: [],
|
11
11
|
dispatch: [],
|
12
|
+
utilization_update: [],
|
12
13
|
quiet: [],
|
13
|
-
shutdown: []
|
14
|
+
shutdown: [],
|
15
|
+
stopped: []
|
14
16
|
}
|
15
17
|
}.freeze
|
16
18
|
|
17
19
|
attr_accessor :active_job_queue_name_prefixing, :cache_visibility_timeout, :groups,
|
18
20
|
:launcher_executor,
|
19
|
-
:start_callback, :stop_callback, :worker_executor, :worker_registry
|
21
|
+
:start_callback, :stop_callback, :worker_executor, :worker_registry, :exception_handlers
|
20
22
|
attr_writer :default_worker_options, :sqs_client
|
21
23
|
attr_reader :sqs_client_receive_message_opts
|
22
24
|
|
23
25
|
def initialize
|
24
26
|
self.groups = {}
|
25
27
|
self.worker_registry = DefaultWorkerRegistry.new
|
28
|
+
self.exception_handlers = [DefaultExceptionHandler]
|
26
29
|
self.active_job_queue_name_prefixing = false
|
27
30
|
self.worker_executor = Worker::DefaultExecutor
|
28
31
|
self.cache_visibility_timeout = false
|
@@ -133,7 +136,7 @@ module Shoryuken
|
|
133
136
|
end
|
134
137
|
|
135
138
|
# Register a block to run at a point in the Shoryuken lifecycle.
|
136
|
-
# :startup, :quiet or :
|
139
|
+
# :startup, :quiet, :shutdown or :stopped are valid events.
|
137
140
|
#
|
138
141
|
# Shoryuken.configure_server do |config|
|
139
142
|
# config.on(:shutdown) do
|
@@ -38,6 +38,13 @@ module Shoryuken
|
|
38
38
|
.reverse
|
39
39
|
end
|
40
40
|
|
41
|
+
def message_processed(queue)
|
42
|
+
if queue_paused?(queue)
|
43
|
+
logger.debug "Unpausing #{queue}"
|
44
|
+
@paused_until[queue] = Time.at 0
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
41
48
|
private
|
42
49
|
|
43
50
|
def next_active_queue
|
@@ -70,6 +77,7 @@ module Shoryuken
|
|
70
77
|
|
71
78
|
def pause(queue)
|
72
79
|
return unless delay > 0
|
80
|
+
|
73
81
|
@paused_until[queue] = Time.now + delay
|
74
82
|
logger.debug "Paused #{queue}"
|
75
83
|
end
|
@@ -35,10 +35,18 @@ module Shoryuken
|
|
35
35
|
unparse_queues(@queues)
|
36
36
|
end
|
37
37
|
|
38
|
+
def message_processed(queue)
|
39
|
+
paused_queue = @paused_queues.find { |_time, name| name == queue }
|
40
|
+
return unless paused_queue
|
41
|
+
|
42
|
+
paused_queue[0] = Time.at 0
|
43
|
+
end
|
44
|
+
|
38
45
|
private
|
39
46
|
|
40
47
|
def pause(queue)
|
41
48
|
return unless @queues.delete(queue)
|
49
|
+
|
42
50
|
@paused_queues << [Time.now + delay, queue]
|
43
51
|
logger.debug "Paused #{queue}"
|
44
52
|
end
|
@@ -46,6 +54,7 @@ module Shoryuken
|
|
46
54
|
def unpause_queues
|
47
55
|
return if @paused_queues.empty?
|
48
56
|
return if Time.now < @paused_queues.first[0]
|
57
|
+
|
49
58
|
pause = @paused_queues.shift
|
50
59
|
@queues << pause[1]
|
51
60
|
logger.debug "Unpaused #{pause[1]}"
|
data/lib/shoryuken/processor.rb
CHANGED
@@ -22,8 +22,7 @@ module Shoryuken
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
rescue Exception => ex
|
25
|
-
|
26
|
-
logger.error { ex.backtrace.join("\n") } unless ex.backtrace.nil?
|
25
|
+
Array(Shoryuken.exception_handlers).each { |handler| handler.call(ex, queue, sqs_msg) }
|
27
26
|
|
28
27
|
raise
|
29
28
|
end
|
data/lib/shoryuken/queue.rb
CHANGED
@@ -21,9 +21,10 @@ module Shoryuken
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def delete_messages(options)
|
24
|
-
client.delete_message_batch(
|
24
|
+
failed_messages = client.delete_message_batch(
|
25
25
|
options.merge(queue_url: url)
|
26
|
-
).failed
|
26
|
+
).failed || []
|
27
|
+
failed_messages.any? do |failure|
|
27
28
|
logger.error do
|
28
29
|
"Could not delete #{failure.id}, code: '#{failure.code}', message: '#{failure.message}', sender_fault: #{failure.sender_fault}"
|
29
30
|
end
|
@@ -43,7 +44,8 @@ module Shoryuken
|
|
43
44
|
end
|
44
45
|
|
45
46
|
def receive_messages(options)
|
46
|
-
client.receive_message(options.merge(queue_url: url)).messages
|
47
|
+
messages = client.receive_message(options.merge(queue_url: url)).messages || []
|
48
|
+
messages.map { |m| Message.new(client, self, m) }
|
47
49
|
end
|
48
50
|
|
49
51
|
def fifo?
|
data/lib/shoryuken/runner.rb
CHANGED
@@ -30,9 +30,6 @@ module Shoryuken
|
|
30
30
|
|
31
31
|
loader = EnvironmentLoader.setup_options(options)
|
32
32
|
|
33
|
-
# When cli args exist, override options in config file
|
34
|
-
Shoryuken.options.merge!(options)
|
35
|
-
|
36
33
|
daemonize(Shoryuken.options)
|
37
34
|
write_pid(Shoryuken.options)
|
38
35
|
|
@@ -55,6 +52,10 @@ module Shoryuken
|
|
55
52
|
end
|
56
53
|
end
|
57
54
|
|
55
|
+
def healthy?
|
56
|
+
(@launcher && @launcher.healthy?) || false
|
57
|
+
end
|
58
|
+
|
58
59
|
private
|
59
60
|
|
60
61
|
def initialize_concurrent_logger
|
data/lib/shoryuken/version.rb
CHANGED