shoryuken 5.0.5 → 6.1.1
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/.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