shoryuken 3.1.3 → 3.2.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/.rubocop.yml +1 -1
- data/.travis.yml +13 -3
- data/CHANGELOG.md +68 -0
- data/Gemfile +5 -3
- data/Gemfile.aws-sdk-core-v2 +13 -0
- data/bin/cli/sqs.rb +8 -4
- data/bin/shoryuken +2 -1
- data/lib/shoryuken/body_parser.rb +27 -0
- data/lib/shoryuken/fetcher.rb +40 -13
- data/lib/shoryuken/launcher.rb +2 -17
- data/lib/shoryuken/manager.rb +17 -5
- data/lib/shoryuken/middleware/chain.rb +4 -0
- data/lib/shoryuken/middleware/server/auto_extend_visibility.rb +2 -5
- data/lib/shoryuken/middleware/server/timing.rb +12 -14
- data/lib/shoryuken/options.rb +21 -1
- data/lib/shoryuken/processor.rb +5 -21
- data/lib/shoryuken/queue.rb +12 -5
- data/lib/shoryuken/runner.rb +3 -1
- data/lib/shoryuken/util.rb +2 -2
- data/lib/shoryuken/version.rb +1 -1
- data/lib/shoryuken/worker/default_executor.rb +33 -0
- data/lib/shoryuken/worker/inline_executor.rb +28 -0
- data/lib/shoryuken/worker.rb +68 -31
- data/lib/shoryuken.rb +12 -0
- data/shoryuken.gemspec +1 -1
- data/spec/shoryuken/body_parser_spec.rb +89 -0
- data/spec/shoryuken/fetcher_spec.rb +61 -9
- data/spec/shoryuken/manager_spec.rb +2 -2
- data/spec/shoryuken/middleware/chain_spec.rb +16 -4
- data/spec/shoryuken/options_spec.rb +80 -0
- data/spec/shoryuken/processor_spec.rb +15 -97
- data/spec/shoryuken/queue_spec.rb +43 -32
- data/spec/shoryuken/util_spec.rb +25 -1
- data/spec/shoryuken/worker/default_executor_spec.rb +100 -0
- data/spec/shoryuken/worker/inline_executor_spec.rb +23 -0
- data/spec/shoryuken/worker_spec.rb +32 -91
- data/spec/spec_helper.rb +2 -0
- metadata +15 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f74e5fbb599fe5bbe41bed5fd542c0c1fdcc2d35
|
|
4
|
+
data.tar.gz: 6099d42682b5e2a1797d7cdbdc7bf27b344b692c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f076e8f427f39ca92be4f27be819350d90270ce9e695d1173a6944b82d16680d11afd78a0075dd549e0a2c6031e6d5708c306cb245c4d7dfcc69d8a5e7151bc7
|
|
7
|
+
data.tar.gz: 2fd34c84e6260df3c35427ffb27d3d067fc1ea11469609d61e8eedd465e4516d75e052079b5195ede7c7917ad3c97bb39c5440bc5436ae3ab2581f3fb72bad31
|
data/.rubocop.yml
CHANGED
data/.travis.yml
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
language: ruby
|
|
2
|
+
|
|
2
3
|
rvm:
|
|
3
4
|
- 2.0.0
|
|
4
|
-
- 2.1.
|
|
5
|
+
- 2.1.10
|
|
5
6
|
- 2.2.0
|
|
6
7
|
- 2.3.3
|
|
7
8
|
- 2.4.1
|
|
@@ -11,9 +12,18 @@ notifications:
|
|
|
11
12
|
on_success: change
|
|
12
13
|
on_failure: always
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
gemfile:
|
|
16
|
+
- Gemfile
|
|
17
|
+
- Gemfile.aws-sdk-core-v2
|
|
18
|
+
|
|
19
|
+
env:
|
|
20
|
+
- SPEC_ALL=true
|
|
21
|
+
|
|
22
|
+
script: bundle exec rspec spec
|
|
23
|
+
|
|
15
24
|
before_install:
|
|
16
|
-
|
|
25
|
+
- gem update bundler
|
|
26
|
+
|
|
17
27
|
after_success:
|
|
18
28
|
- bundle exec codeclimate-test-reporter
|
|
19
29
|
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,71 @@
|
|
|
1
|
+
## [v3.2.0] - 2018-01-03
|
|
2
|
+
|
|
3
|
+
- Preserve parent worker class options
|
|
4
|
+
- [#451](https://github.com/phstc/shoryuken/pull/451)
|
|
5
|
+
|
|
6
|
+
- Add -t (shutdown timeout) option to CL
|
|
7
|
+
- [#449](https://github.com/phstc/shoryuken/pull/449)
|
|
8
|
+
|
|
9
|
+
- Support inline (Active Job like) for standard workers
|
|
10
|
+
- [#448](https://github.com/phstc/shoryuken/pull/448)
|
|
11
|
+
|
|
12
|
+
## [v3.1.12] - 2017-09-25
|
|
13
|
+
|
|
14
|
+
- Reduce fetch log verbosity
|
|
15
|
+
- [#436](https://github.com/phstc/shoryuken/pull/436)
|
|
16
|
+
|
|
17
|
+
## [v3.1.11] - 2017-09-02
|
|
18
|
+
|
|
19
|
+
- Auto retry (up to 3 times) fetch errors
|
|
20
|
+
- [#429](https://github.com/phstc/shoryuken/pull/429)
|
|
21
|
+
|
|
22
|
+
## [v3.1.10] - 2017-09-02
|
|
23
|
+
|
|
24
|
+
- Make Shoryuken compatible with AWS SDK 3 and 2
|
|
25
|
+
- [#433](https://github.com/phstc/shoryuken/pull/433)
|
|
26
|
+
|
|
27
|
+
## [v3.1.9] - 2017-08-24
|
|
28
|
+
|
|
29
|
+
- Add support for adding a middleware to the front of chain
|
|
30
|
+
- [#427](https://github.com/phstc/shoryuken/pull/427)
|
|
31
|
+
|
|
32
|
+
- Add support for dispatch fire event
|
|
33
|
+
- [#426](https://github.com/phstc/shoryuken/pull/426)
|
|
34
|
+
|
|
35
|
+
## [v3.1.8] - 2017-08-17
|
|
36
|
+
|
|
37
|
+
- Make Polling strategy backward compatibility
|
|
38
|
+
- [#424](https://github.com/phstc/shoryuken/pull/424)
|
|
39
|
+
|
|
40
|
+
## [v3.1.7] - 2017-07-31
|
|
41
|
+
|
|
42
|
+
- Allow polling strategy per group
|
|
43
|
+
- [#417](https://github.com/phstc/shoryuken/pull/417)
|
|
44
|
+
|
|
45
|
+
- Add support for creating FIFO queues
|
|
46
|
+
- [#419](https://github.com/phstc/shoryuken/pull/419)
|
|
47
|
+
|
|
48
|
+
- Allow receive message options per queue
|
|
49
|
+
- [#420](https://github.com/phstc/shoryuken/pull/420)
|
|
50
|
+
|
|
51
|
+
## [v3.1.6] - 2017-07-24
|
|
52
|
+
|
|
53
|
+
- Fix issue with dispatch_loop and delays
|
|
54
|
+
- [#416](https://github.com/phstc/shoryuken/pull/416)
|
|
55
|
+
|
|
56
|
+
## [v3.1.5] - 2017-07-23
|
|
57
|
+
|
|
58
|
+
- Fix memory leak
|
|
59
|
+
- [#414](https://github.com/phstc/shoryuken/pull/414)
|
|
60
|
+
|
|
61
|
+
- Fail fast on bad queue URLs
|
|
62
|
+
- [#413](https://github.com/phstc/shoryuken/pull/413)
|
|
63
|
+
|
|
64
|
+
## [v3.1.4] - 2017-07-14
|
|
65
|
+
|
|
66
|
+
- Require forwardable allowding to call `shoryuken` without `bundle exec`
|
|
67
|
+
- [#409](https://github.com/phstc/shoryuken/pull/409)
|
|
68
|
+
|
|
1
69
|
## [v3.1.3] - 2017-07-11
|
|
2
70
|
|
|
3
71
|
- Add queue prefixing support for groups
|
data/Gemfile
CHANGED
|
@@ -4,9 +4,11 @@ source 'https://rubygems.org'
|
|
|
4
4
|
gemspec
|
|
5
5
|
|
|
6
6
|
group :test do
|
|
7
|
-
gem 'activejob'
|
|
7
|
+
gem 'activejob', '~> 4'
|
|
8
|
+
gem 'aws-sdk-core', '~> 3'
|
|
9
|
+
gem 'aws-sdk-sqs'
|
|
8
10
|
gem 'codeclimate-test-reporter', require: nil
|
|
9
|
-
gem 'simplecov'
|
|
10
|
-
gem 'multi_xml'
|
|
11
11
|
gem 'httparty'
|
|
12
|
+
gem 'multi_xml'
|
|
13
|
+
gem 'simplecov'
|
|
12
14
|
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
source 'https://rubygems.org'
|
|
2
|
+
|
|
3
|
+
# Specify your gem's dependencies in shoryuken.gemspec
|
|
4
|
+
gemspec
|
|
5
|
+
|
|
6
|
+
group :test do
|
|
7
|
+
gem 'activejob', '~> 4'
|
|
8
|
+
gem 'aws-sdk-core', '~> 2'
|
|
9
|
+
gem 'codeclimate-test-reporter', require: nil
|
|
10
|
+
gem 'httparty'
|
|
11
|
+
gem 'multi_xml'
|
|
12
|
+
gem 'simplecov'
|
|
13
|
+
end
|
data/bin/cli/sqs.rb
CHANGED
|
@@ -96,8 +96,8 @@ module Shoryuken
|
|
|
96
96
|
end
|
|
97
97
|
|
|
98
98
|
desc 'ls [QUEUE-NAME-PREFIX]', 'Lists queues'
|
|
99
|
-
method_option :watch,
|
|
100
|
-
method_option :
|
|
99
|
+
method_option :watch, aliases: '-w', type: :boolean, desc: 'watch queues'
|
|
100
|
+
method_option :interval, aliases: '-n', type: :numeric, default: 2, desc: 'watch interval in seconds'
|
|
101
101
|
def ls(queue_name_prefix = '')
|
|
102
102
|
trap('SIGINT', 'EXIT') # expect ctrl-c from loop
|
|
103
103
|
|
|
@@ -108,7 +108,7 @@ module Shoryuken
|
|
|
108
108
|
|
|
109
109
|
break unless options[:watch]
|
|
110
110
|
|
|
111
|
-
sleep options[:
|
|
111
|
+
sleep options[:interval]
|
|
112
112
|
puts
|
|
113
113
|
end
|
|
114
114
|
end
|
|
@@ -187,8 +187,12 @@ module Shoryuken
|
|
|
187
187
|
end
|
|
188
188
|
|
|
189
189
|
desc 'create QUEUE-NAME', 'Create a queue'
|
|
190
|
+
method_option :attributes, aliases: '-a', type: :hash, default: {}, desc: 'queue attributes'
|
|
190
191
|
def create(queue_name)
|
|
191
|
-
|
|
192
|
+
attributes = options[:attributes]
|
|
193
|
+
attributes['FifoQueue'] ||= 'true' if queue_name.end_with?('.fifo')
|
|
194
|
+
|
|
195
|
+
queue_url = sqs.create_queue(queue_name: queue_name, attributes: attributes).queue_url
|
|
192
196
|
|
|
193
197
|
say "Queue #{queue_name} was successfully created. Queue URL #{queue_url}", :green
|
|
194
198
|
end
|
data/bin/shoryuken
CHANGED
|
@@ -21,6 +21,7 @@ module Shoryuken
|
|
|
21
21
|
method_option :daemon, aliases: '-d', type: :boolean, desc: 'Daemonize process'
|
|
22
22
|
method_option :queues, aliases: '-q', type: :array, desc: 'Queues to process with optional weights'
|
|
23
23
|
method_option :require, aliases: '-r', type: :string, desc: 'Dir or path of the workers'
|
|
24
|
+
method_option :timeout, aliases: '-t', type: :numeric, desc: 'Hard shutdown timeout'
|
|
24
25
|
method_option :config, aliases: '-C', type: :string, desc: 'Path to config file'
|
|
25
26
|
method_option :config_file, type: :string, desc: 'Path to config file (backwards compatibility)'
|
|
26
27
|
method_option :rails, aliases: '-R', type: :boolean, desc: 'Load Rails'
|
|
@@ -32,7 +33,7 @@ module Shoryuken
|
|
|
32
33
|
opts = options.to_h.symbolize_keys
|
|
33
34
|
|
|
34
35
|
if opts[:config_file]
|
|
35
|
-
say
|
|
36
|
+
say '[DEPRECATED] Please use --config instead of --config-file', :yellow
|
|
36
37
|
end
|
|
37
38
|
|
|
38
39
|
opts[:config_file] = opts.delete(:config) if opts[:config]
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Shoryuken
|
|
2
|
+
class BodyParser
|
|
3
|
+
class << self
|
|
4
|
+
def parse(worker_class, sqs_msg)
|
|
5
|
+
body_parser = worker_class.get_shoryuken_options['body_parser']
|
|
6
|
+
|
|
7
|
+
case body_parser
|
|
8
|
+
when :json
|
|
9
|
+
JSON.parse(sqs_msg.body)
|
|
10
|
+
when Proc
|
|
11
|
+
body_parser.call(sqs_msg)
|
|
12
|
+
when :text, nil
|
|
13
|
+
sqs_msg.body
|
|
14
|
+
else
|
|
15
|
+
if body_parser.respond_to?(:parse)
|
|
16
|
+
# JSON.parse
|
|
17
|
+
body_parser.parse(sqs_msg.body)
|
|
18
|
+
elsif body_parser.respond_to?(:load)
|
|
19
|
+
# see https://github.com/phstc/shoryuken/pull/91
|
|
20
|
+
# JSON.load
|
|
21
|
+
body_parser.load(sqs_msg.body)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
data/lib/shoryuken/fetcher.rb
CHANGED
|
@@ -4,34 +4,50 @@ module Shoryuken
|
|
|
4
4
|
|
|
5
5
|
FETCH_LIMIT = 10
|
|
6
6
|
|
|
7
|
-
attr_reader :group
|
|
8
|
-
|
|
9
7
|
def initialize(group)
|
|
10
8
|
@group = group
|
|
11
9
|
end
|
|
12
10
|
|
|
13
11
|
def fetch(queue, limit)
|
|
14
|
-
|
|
12
|
+
fetch_with_auto_retry(3) do
|
|
13
|
+
started_at = Time.now
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
logger.debug { "Looking for new messages in #{queue}" }
|
|
17
16
|
|
|
18
|
-
|
|
17
|
+
sqs_msgs = Array(receive_messages(queue, [FETCH_LIMIT, limit].min))
|
|
19
18
|
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
logger.debug { "Found #{sqs_msgs.size} messages for #{queue.name}" } unless sqs_msgs.empty?
|
|
20
|
+
logger.debug { "Fetcher for #{queue} completed in #{elapsed(started_at)} ms" }
|
|
22
21
|
|
|
23
|
-
|
|
22
|
+
sqs_msgs
|
|
23
|
+
end
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
private
|
|
27
27
|
|
|
28
|
-
def
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
def fetch_with_auto_retry(max_attempts, &block)
|
|
29
|
+
attempts = 0
|
|
30
|
+
|
|
31
|
+
begin
|
|
32
|
+
yield
|
|
33
|
+
rescue => ex
|
|
34
|
+
# Tries to auto retry connectivity errors
|
|
35
|
+
raise if attempts >= max_attempts
|
|
36
|
+
|
|
37
|
+
attempts += 1
|
|
38
|
+
|
|
39
|
+
logger.debug { "Retrying fetch attempt #{attempts} for #{ex.message}" }
|
|
40
|
+
|
|
41
|
+
sleep((1..5).to_a.sample)
|
|
42
|
+
|
|
43
|
+
retry
|
|
44
|
+
end
|
|
45
|
+
end
|
|
31
46
|
|
|
32
|
-
|
|
47
|
+
def receive_messages(queue, limit)
|
|
48
|
+
options = receive_options(queue)
|
|
33
49
|
|
|
34
|
-
options[:max_number_of_messages] = limit
|
|
50
|
+
options[:max_number_of_messages] = max_number_of_messages(limit, options)
|
|
35
51
|
options[:message_attribute_names] = %w(All)
|
|
36
52
|
options[:attribute_names] = %w(All)
|
|
37
53
|
|
|
@@ -39,5 +55,16 @@ module Shoryuken
|
|
|
39
55
|
|
|
40
56
|
Shoryuken::Client.queues(queue.name).receive_messages(options)
|
|
41
57
|
end
|
|
58
|
+
|
|
59
|
+
def max_number_of_messages(limit, options)
|
|
60
|
+
[limit, FETCH_LIMIT, options[:max_number_of_messages]].compact.min
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def receive_options(queue)
|
|
64
|
+
options = Shoryuken.sqs_client_receive_message_opts[queue.name]
|
|
65
|
+
options ||= Shoryuken.sqs_client_receive_message_opts[@group]
|
|
66
|
+
|
|
67
|
+
options.to_h.dup
|
|
68
|
+
end
|
|
42
69
|
end
|
|
43
70
|
end
|
data/lib/shoryuken/launcher.rb
CHANGED
|
@@ -3,8 +3,7 @@ module Shoryuken
|
|
|
3
3
|
include Util
|
|
4
4
|
|
|
5
5
|
def initialize
|
|
6
|
-
@managers
|
|
7
|
-
@shutdowning = Concurrent::AtomicBoolean.new(false)
|
|
6
|
+
@managers = create_managers
|
|
8
7
|
end
|
|
9
8
|
|
|
10
9
|
def start
|
|
@@ -41,24 +40,10 @@ module Shoryuken
|
|
|
41
40
|
|
|
42
41
|
def start_managers
|
|
43
42
|
@managers.each do |manager|
|
|
44
|
-
Concurrent::
|
|
45
|
-
log_manager_failure(ex)
|
|
46
|
-
start_soft_shutdown
|
|
47
|
-
end
|
|
43
|
+
Concurrent::Future.execute { manager.start }
|
|
48
44
|
end
|
|
49
45
|
end
|
|
50
46
|
|
|
51
|
-
def start_soft_shutdown
|
|
52
|
-
Process.kill('USR1', Process.pid) if @shutdowning.make_true
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def log_manager_failure(ex)
|
|
56
|
-
return unless ex
|
|
57
|
-
|
|
58
|
-
logger.error { "Manager failed: #{ex.message}" }
|
|
59
|
-
logger.error { ex.backtrace.join("\n") } unless ex.backtrace.nil?
|
|
60
|
-
end
|
|
61
|
-
|
|
62
47
|
def initiate_stop
|
|
63
48
|
logger.info { 'Shutting down' }
|
|
64
49
|
|
data/lib/shoryuken/manager.rb
CHANGED
|
@@ -12,6 +12,7 @@ module Shoryuken
|
|
|
12
12
|
@max_processors = concurrency
|
|
13
13
|
@busy_processors = Concurrent::AtomicFixnum.new(0)
|
|
14
14
|
@executor = executor
|
|
15
|
+
@running = Concurrent::AtomicBoolean.new(true)
|
|
15
16
|
end
|
|
16
17
|
|
|
17
18
|
def start
|
|
@@ -21,15 +22,13 @@ module Shoryuken
|
|
|
21
22
|
private
|
|
22
23
|
|
|
23
24
|
def running?
|
|
24
|
-
@executor.running?
|
|
25
|
+
@running.true? && @executor.running?
|
|
25
26
|
end
|
|
26
27
|
|
|
27
28
|
def dispatch_loop
|
|
28
29
|
return unless running?
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
executor: @executor
|
|
32
|
-
) { dispatch }.then { dispatch_loop }.rescue { |ex| raise ex }
|
|
31
|
+
@executor.post { dispatch }
|
|
33
32
|
end
|
|
34
33
|
|
|
35
34
|
def dispatch
|
|
@@ -39,11 +38,15 @@ module Shoryuken
|
|
|
39
38
|
return sleep(MIN_DISPATCH_INTERVAL)
|
|
40
39
|
end
|
|
41
40
|
|
|
42
|
-
fire_event(:dispatch)
|
|
41
|
+
fire_event(:dispatch, false, queue_name: queue.name)
|
|
43
42
|
|
|
44
43
|
logger.debug { "Ready: #{ready}, Busy: #{busy}, Active Queues: #{@polling_strategy.active_queues}" }
|
|
45
44
|
|
|
46
45
|
batched_queue?(queue) ? dispatch_batch(queue) : dispatch_single_messages(queue)
|
|
46
|
+
rescue => ex
|
|
47
|
+
handle_dispatch_error(ex)
|
|
48
|
+
ensure
|
|
49
|
+
dispatch_loop
|
|
47
50
|
end
|
|
48
51
|
|
|
49
52
|
def busy
|
|
@@ -96,5 +99,14 @@ module Shoryuken
|
|
|
96
99
|
|
|
97
100
|
sqs_msgs
|
|
98
101
|
end
|
|
102
|
+
|
|
103
|
+
def handle_dispatch_error(ex)
|
|
104
|
+
logger.error { "Manager failed: #{ex.message}" }
|
|
105
|
+
logger.error { ex.backtrace.join("\n") } unless ex.backtrace.nil?
|
|
106
|
+
|
|
107
|
+
Process.kill('USR1', Process.pid)
|
|
108
|
+
|
|
109
|
+
@running.make_false
|
|
110
|
+
end
|
|
99
111
|
end
|
|
100
112
|
end
|
|
@@ -61,6 +61,10 @@ module Shoryuken
|
|
|
61
61
|
entries << Entry.new(klass, *args) unless exists?(klass)
|
|
62
62
|
end
|
|
63
63
|
|
|
64
|
+
def prepend(klass, *args)
|
|
65
|
+
entries.insert(0, Entry.new(klass, *args)) unless exists?(klass)
|
|
66
|
+
end
|
|
67
|
+
|
|
64
68
|
def insert_before(oldklass, newklass, *args)
|
|
65
69
|
i = entries.index { |entry| entry.klass == newklass }
|
|
66
70
|
new_entry = i.nil? ? Entry.new(newklass, *args) : entries.delete_at(i)
|
|
@@ -31,16 +31,13 @@ module Shoryuken
|
|
|
31
31
|
Concurrent::TimerTask.new(execution_interval: queue_visibility_timeout - EXTEND_UPFRONT_SECONDS) do
|
|
32
32
|
begin
|
|
33
33
|
logger.debug do
|
|
34
|
-
"Extending message #{
|
|
35
|
-
"visibility timeout by #{queue_visibility_timeout}s."
|
|
34
|
+
"Extending message #{queue}/#{sqs_msg.message_id} visibility timeout by #{queue_visibility_timeout}s"
|
|
36
35
|
end
|
|
37
36
|
|
|
38
37
|
sqs_msg.change_visibility(visibility_timeout: queue_visibility_timeout)
|
|
39
38
|
rescue => ex
|
|
40
39
|
logger.error do
|
|
41
|
-
|
|
42
|
-
"#{worker_name(worker.class, sqs_msg, body)}/#{queue}/#{sqs_msg.message_id} " \
|
|
43
|
-
"visibility timeout. Error: #{ex.message}"
|
|
40
|
+
"Could not auto extend the message #{queue}/#{sqs_msg.message_id} visibility timeout. Error: #{ex.message}"
|
|
44
41
|
end
|
|
45
42
|
end
|
|
46
43
|
end
|
|
@@ -5,25 +5,23 @@ module Shoryuken
|
|
|
5
5
|
include Util
|
|
6
6
|
|
|
7
7
|
def call(worker, queue, sqs_msg, body)
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
started_at = Time.now
|
|
8
|
+
begin
|
|
9
|
+
started_at = Time.now
|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
logger.info { "started at #{started_at}" }
|
|
13
12
|
|
|
14
|
-
|
|
13
|
+
yield
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
total_time = elapsed(started_at)
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
logger.info { "completed in: #{total_time} ms" }
|
|
23
|
-
rescue
|
|
24
|
-
logger.info { "failed in: #{elapsed(started_at)} ms" }
|
|
25
|
-
raise
|
|
17
|
+
if (total_time / 1000.0) > (timeout = Shoryuken::Client.queues(queue).visibility_timeout)
|
|
18
|
+
logger.warn { "exceeded the queue visibility timeout by #{total_time - (timeout * 1000)} ms" }
|
|
26
19
|
end
|
|
20
|
+
|
|
21
|
+
logger.info { "completed in: #{total_time} ms" }
|
|
22
|
+
rescue
|
|
23
|
+
logger.info { "failed in: #{elapsed(started_at)} ms" }
|
|
24
|
+
raise
|
|
27
25
|
end
|
|
28
26
|
end
|
|
29
27
|
end
|
data/lib/shoryuken/options.rb
CHANGED
|
@@ -21,6 +21,7 @@ module Shoryuken
|
|
|
21
21
|
@@sqs_client_receive_message_opts = {}
|
|
22
22
|
@@start_callback = nil
|
|
23
23
|
@@stop_callback = nil
|
|
24
|
+
@@worker_executor = Worker::DefaultExecutor
|
|
24
25
|
|
|
25
26
|
class << self
|
|
26
27
|
def active_job?
|
|
@@ -56,8 +57,27 @@ module Shoryuken
|
|
|
56
57
|
@@worker_registry = worker_registry
|
|
57
58
|
end
|
|
58
59
|
|
|
60
|
+
def worker_executor
|
|
61
|
+
@@worker_executor
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def worker_executor=(worker_executor)
|
|
65
|
+
@@worker_executor = worker_executor
|
|
66
|
+
end
|
|
67
|
+
|
|
59
68
|
def polling_strategy(group)
|
|
60
|
-
options[group].to_h
|
|
69
|
+
strategy = (group == 'default' ? options : options[:groups].to_h[group]).to_h[:polling_strategy]
|
|
70
|
+
|
|
71
|
+
case strategy
|
|
72
|
+
when 'WeightedRoundRobin', nil # Default case
|
|
73
|
+
Polling::WeightedRoundRobin
|
|
74
|
+
when 'StrictPriority'
|
|
75
|
+
Polling::StrictPriority
|
|
76
|
+
when Class
|
|
77
|
+
strategy
|
|
78
|
+
else
|
|
79
|
+
raise ArgumentError, "#{strategy} is not a valid polling_strategy"
|
|
80
|
+
end
|
|
61
81
|
end
|
|
62
82
|
|
|
63
83
|
def start_callback
|
data/lib/shoryuken/processor.rb
CHANGED
|
@@ -16,8 +16,10 @@ module Shoryuken
|
|
|
16
16
|
def process
|
|
17
17
|
return logger.error { "No worker found for #{queue}" } unless worker
|
|
18
18
|
|
|
19
|
-
worker.class
|
|
20
|
-
worker.
|
|
19
|
+
Shoryuken::Logging.with_context("#{worker_name(worker.class, sqs_msg, body)}/#{queue}/#{sqs_msg.message_id}") do
|
|
20
|
+
worker.class.server_middleware.invoke(worker, queue, sqs_msg, body) do
|
|
21
|
+
worker.perform(sqs_msg, body)
|
|
22
|
+
end
|
|
21
23
|
end
|
|
22
24
|
rescue Exception => ex
|
|
23
25
|
logger.error { "Processor failed: #{ex.message}" }
|
|
@@ -41,25 +43,7 @@ module Shoryuken
|
|
|
41
43
|
end
|
|
42
44
|
|
|
43
45
|
def parse_body(sqs_msg)
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
case body_parser
|
|
47
|
-
when :json
|
|
48
|
-
JSON.parse(sqs_msg.body)
|
|
49
|
-
when Proc
|
|
50
|
-
body_parser.call(sqs_msg)
|
|
51
|
-
when :text, nil
|
|
52
|
-
sqs_msg.body
|
|
53
|
-
else
|
|
54
|
-
if body_parser.respond_to?(:parse)
|
|
55
|
-
# JSON.parse
|
|
56
|
-
body_parser.parse(sqs_msg.body)
|
|
57
|
-
elsif body_parser.respond_to?(:load)
|
|
58
|
-
# see https://github.com/phstc/shoryuken/pull/91
|
|
59
|
-
# JSON.load
|
|
60
|
-
body_parser.load(sqs_msg.body)
|
|
61
|
-
end
|
|
62
|
-
end
|
|
46
|
+
BodyParser.parse(worker_class, sqs_msg)
|
|
63
47
|
end
|
|
64
48
|
end
|
|
65
49
|
end
|
data/lib/shoryuken/queue.rb
CHANGED
|
@@ -49,20 +49,27 @@ module Shoryuken
|
|
|
49
49
|
|
|
50
50
|
private
|
|
51
51
|
|
|
52
|
-
def
|
|
52
|
+
def set_by_name(name)
|
|
53
53
|
self.name = name
|
|
54
54
|
self.url = client.get_queue_url(queue_name: name).queue_url
|
|
55
|
-
rescue Aws::Errors::NoSuchEndpointError, Aws::SQS::Errors::NonExistentQueue => ex
|
|
56
|
-
raise ex, "The specified queue #{name} does not exist."
|
|
57
55
|
end
|
|
58
56
|
|
|
59
|
-
def
|
|
57
|
+
def set_by_url(url)
|
|
60
58
|
self.name = url.split('/').last
|
|
61
59
|
self.url = url
|
|
62
60
|
end
|
|
63
61
|
|
|
64
62
|
def set_name_and_url(name_or_url)
|
|
65
|
-
name_or_url.start_with?('https://sqs.')
|
|
63
|
+
if name_or_url.start_with?('https://sqs.')
|
|
64
|
+
set_by_url(name_or_url)
|
|
65
|
+
|
|
66
|
+
# anticipate the fifo? checker for validating the queue URL
|
|
67
|
+
return fifo?
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
set_by_name(name_or_url)
|
|
71
|
+
rescue Aws::Errors::NoSuchEndpointError, Aws::SQS::Errors::NonExistentQueue => ex
|
|
72
|
+
raise ex, "The specified queue #{name_or_url} does not exist."
|
|
66
73
|
end
|
|
67
74
|
|
|
68
75
|
def queue_attributes
|
data/lib/shoryuken/runner.rb
CHANGED
|
@@ -118,10 +118,12 @@ module Shoryuken
|
|
|
118
118
|
end
|
|
119
119
|
|
|
120
120
|
def handle_signal(sig)
|
|
121
|
+
logger.debug "Got #{sig} signal"
|
|
122
|
+
|
|
121
123
|
case sig
|
|
122
124
|
when 'USR1' then execute_soft_shutdown
|
|
123
125
|
when 'TTIN' then print_threads_backtrace
|
|
124
|
-
|
|
126
|
+
when 'TERM', 'INT'
|
|
125
127
|
logger.info { "Received #{sig}, will shutdown down" }
|
|
126
128
|
|
|
127
129
|
raise Interrupt
|
data/lib/shoryuken/util.rb
CHANGED
|
@@ -4,13 +4,13 @@ module Shoryuken
|
|
|
4
4
|
Shoryuken.logger
|
|
5
5
|
end
|
|
6
6
|
|
|
7
|
-
def fire_event(event, reverse = false)
|
|
7
|
+
def fire_event(event, reverse = false, event_options = {})
|
|
8
8
|
logger.debug { "Firing '#{event}' lifecycle event" }
|
|
9
9
|
arr = Shoryuken.options[:lifecycle_events][event]
|
|
10
10
|
arr.reverse! if reverse
|
|
11
11
|
arr.each do |block|
|
|
12
12
|
begin
|
|
13
|
-
block.call
|
|
13
|
+
block.call(event_options)
|
|
14
14
|
rescue => ex
|
|
15
15
|
logger.warn(event: event)
|
|
16
16
|
logger.warn "#{ex.class.name}: #{ex.message}"
|
data/lib/shoryuken/version.rb
CHANGED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module Shoryuken
|
|
2
|
+
module Worker
|
|
3
|
+
class DefaultExecutor
|
|
4
|
+
class << self
|
|
5
|
+
def perform_async(worker_class, body, options = {})
|
|
6
|
+
options[:message_attributes] ||= {}
|
|
7
|
+
options[:message_attributes]['shoryuken_class'] = {
|
|
8
|
+
string_value: worker_class.to_s,
|
|
9
|
+
data_type: 'String'
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
options[:message_body] = body
|
|
13
|
+
|
|
14
|
+
queue = options.delete(:queue) || worker_class.get_shoryuken_options['queue']
|
|
15
|
+
|
|
16
|
+
Shoryuken::Client.queues(queue).send_message(options)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def perform_in(worker_class, interval, body, options = {})
|
|
20
|
+
interval = interval.to_f
|
|
21
|
+
now = Time.now.to_f
|
|
22
|
+
ts = (interval < 1_000_000_000 ? (now + interval).to_f : interval)
|
|
23
|
+
|
|
24
|
+
delay = (ts - now).ceil
|
|
25
|
+
|
|
26
|
+
raise 'The maximum allowed delay is 15 minutes' if delay > 15 * 60
|
|
27
|
+
|
|
28
|
+
worker_class.perform_async(body, options.merge(delay_seconds: delay))
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|