shoryuken 3.1.0 → 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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/.travis.yml +13 -3
  4. data/CHANGELOG.md +89 -0
  5. data/Gemfile +5 -2
  6. data/Gemfile.aws-sdk-core-v2 +13 -0
  7. data/bin/cli/sqs.rb +8 -4
  8. data/bin/shoryuken +2 -1
  9. data/lib/shoryuken/body_parser.rb +27 -0
  10. data/lib/shoryuken/environment_loader.rb +25 -11
  11. data/lib/shoryuken/fetcher.rb +40 -13
  12. data/lib/shoryuken/launcher.rb +4 -20
  13. data/lib/shoryuken/logging.rb +0 -5
  14. data/lib/shoryuken/manager.rb +33 -24
  15. data/lib/shoryuken/middleware/chain.rb +4 -0
  16. data/lib/shoryuken/middleware/server/auto_extend_visibility.rb +2 -5
  17. data/lib/shoryuken/middleware/server/timing.rb +12 -14
  18. data/lib/shoryuken/options.rb +25 -1
  19. data/lib/shoryuken/processor.rb +9 -21
  20. data/lib/shoryuken/queue.rb +12 -5
  21. data/lib/shoryuken/runner.rb +3 -1
  22. data/lib/shoryuken/util.rb +3 -3
  23. data/lib/shoryuken/version.rb +1 -1
  24. data/lib/shoryuken/worker/default_executor.rb +33 -0
  25. data/lib/shoryuken/worker/inline_executor.rb +28 -0
  26. data/lib/shoryuken/worker.rb +68 -31
  27. data/lib/shoryuken.rb +14 -1
  28. data/shoryuken.gemspec +1 -1
  29. data/spec/shoryuken/body_parser_spec.rb +89 -0
  30. data/spec/shoryuken/environment_loader_spec.rb +32 -3
  31. data/spec/shoryuken/fetcher_spec.rb +61 -9
  32. data/spec/shoryuken/manager_spec.rb +49 -20
  33. data/spec/shoryuken/middleware/chain_spec.rb +16 -4
  34. data/spec/shoryuken/middleware/server/timing_spec.rb +5 -3
  35. data/spec/shoryuken/options_spec.rb +80 -0
  36. data/spec/shoryuken/processor_spec.rb +15 -97
  37. data/spec/shoryuken/queue_spec.rb +43 -32
  38. data/spec/shoryuken/util_spec.rb +25 -1
  39. data/spec/shoryuken/worker/default_executor_spec.rb +100 -0
  40. data/spec/shoryuken/worker/inline_executor_spec.rb +23 -0
  41. data/spec/shoryuken/worker_spec.rb +32 -91
  42. data/spec/spec_helper.rb +5 -0
  43. metadata +15 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 779c3e9c7f708f0a6dccb3e8b0c9f7e2490b25e1
4
- data.tar.gz: bf260a2793ff8c07ddfb670832ba5f12af8d85d9
3
+ metadata.gz: f74e5fbb599fe5bbe41bed5fd542c0c1fdcc2d35
4
+ data.tar.gz: 6099d42682b5e2a1797d7cdbdc7bf27b344b692c
5
5
  SHA512:
6
- metadata.gz: 1f3e7a4b668c929daa1b5424b7a8ab7f028238b3f6dfe0e812351991bbc37923b58491760df6e4ed4921624cd4954761daeac257c6a540fd193d160d121044de
7
- data.tar.gz: 02f2bf2e813cbe1624ae83d16936196ecf523fe8d3773f9b0c39813aa0822d3c71fd273ee01a63072c20d86bf05f4c1a775eda3fae41cec4bf55ea567f772aef
6
+ metadata.gz: f076e8f427f39ca92be4f27be819350d90270ce9e695d1173a6944b82d16680d11afd78a0075dd549e0a2c6031e6d5708c306cb245c4d7dfcc69d8a5e7151bc7
7
+ data.tar.gz: 2fd34c84e6260df3c35427ffb27d3d067fc1ea11469609d61e8eedd465e4516d75e052079b5195ede7c7917ad3c97bb39c5440bc5436ae3ab2581f3fb72bad31
data/.rubocop.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  AllCops:
2
- TargetRubyVersion: 2.0
2
+ TargetRubyVersion: 2.1
3
3
 
4
4
  Style/SignalException:
5
5
  Enabled: false
data/.travis.yml CHANGED
@@ -1,7 +1,8 @@
1
1
  language: ruby
2
+
2
3
  rvm:
3
4
  - 2.0.0
4
- - 2.1.0
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
- script: SPEC_ALL=true bundle exec rspec spec
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
- - gem update bundler
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,92 @@
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
+
69
+ ## [v3.1.3] - 2017-07-11
70
+
71
+ - Add queue prefixing support for groups
72
+ - [#405](https://github.com/phstc/shoryuken/pull/405)
73
+
74
+ - Remove dead code
75
+ - [#402](https://github.com/phstc/shoryuken/pull/402)
76
+
77
+ ## [v3.1.2] - 2017-07-06
78
+
79
+ - Fix stack level too deep on Ubuntu
80
+ - [#400](https://github.com/phstc/shoryuken/pull/400)
81
+
82
+ ## [v3.1.1] - 2017-07-05
83
+
84
+ - Reduce log verbosity introduced in 3.1.0
85
+ - [#397](https://github.com/phstc/shoryuken/pull/397)
86
+
87
+ - Try to prevent stack level too deep on Ubuntu
88
+ - [#396](https://github.com/phstc/shoryuken/pull/396)
89
+
1
90
  ## [v3.1.0] - 2017-07-02
2
91
 
3
92
  - Add shoryuken sqs delete command
data/Gemfile CHANGED
@@ -4,8 +4,11 @@ source 'https://rubygems.org'
4
4
  gemspec
5
5
 
6
6
  group :test do
7
+ gem 'activejob', '~> 4'
8
+ gem 'aws-sdk-core', '~> 3'
9
+ gem 'aws-sdk-sqs'
7
10
  gem 'codeclimate-test-reporter', require: nil
8
- gem 'simplecov'
9
- gem 'multi_xml'
10
11
  gem 'httparty'
12
+ gem 'multi_xml'
13
+ gem 'simplecov'
11
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, aliases: '-w', type: :boolean, desc: 'watch queues'
100
- method_option :watch_interval, type: :numeric, default: 10, desc: 'watch interval'
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[:watch_interval]
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
- queue_url = sqs.create_queue(queue_name: queue_name).queue_url
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 "[DEPRECATED] Please use --config instead of --config-file", :yellow
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
@@ -44,7 +44,7 @@ module Shoryuken
44
44
 
45
45
  fail ArgumentError, "The supplied config file #{path} does not exist" unless File.exist?(path)
46
46
 
47
- if result = YAML.load(ERB.new(IO.read(path)).result)
47
+ if (result = YAML.load(ERB.new(IO.read(path)).result))
48
48
  result.deep_symbolize_keys
49
49
  else
50
50
  {}
@@ -69,7 +69,7 @@ module Shoryuken
69
69
  ::Rails::Application.initializer 'shoryuken.eager_load' do
70
70
  ::Rails.application.config.eager_load = true
71
71
  end
72
- require 'shoryuken/extensions/active_job_adapter' if defined?(::ActiveJob)
72
+ require 'shoryuken/extensions/active_job_adapter' if Shoryuken.active_job?
73
73
  require File.expand_path('config/environment.rb')
74
74
  end
75
75
  end
@@ -85,22 +85,36 @@ module Shoryuken
85
85
  end
86
86
  end
87
87
 
88
- def prefix_active_job_queue_names
89
- return unless defined? ::ActiveJob
90
- return unless Shoryuken.active_job_queue_name_prefixing
91
-
88
+ def prefix_active_job_queue_name(queue_name, weight)
92
89
  queue_name_prefix = ::ActiveJob::Base.queue_name_prefix
93
90
  queue_name_delimiter = ::ActiveJob::Base.queue_name_delimiter
94
91
 
95
92
  # See https://github.com/rails/rails/blob/master/activejob/lib/active_job/queue_name.rb#L27
93
+ name_parts = [queue_name_prefix.presence, queue_name]
94
+ prefixed_queue_name = name_parts.compact.join(queue_name_delimiter)
95
+ [prefixed_queue_name, weight]
96
+ end
97
+
98
+ def prefix_active_job_queue_names
99
+ return unless Shoryuken.active_job?
100
+ return unless Shoryuken.active_job_queue_name_prefixing
101
+
96
102
  Shoryuken.options[:queues].to_a.map! do |queue_name, weight|
97
- name_parts = [queue_name_prefix.presence, queue_name]
98
- prefixed_queue_name = name_parts.compact.join(queue_name_delimiter)
99
- [prefixed_queue_name, weight]
103
+ prefix_active_job_queue_name(queue_name, weight)
104
+ end
105
+
106
+ Shoryuken.options[:groups].to_a.map! do |group, options|
107
+ if options[:queues]
108
+ options[:queues].map! do |queue_name, weight|
109
+ prefix_active_job_queue_name(queue_name, weight)
110
+ end
111
+ end
112
+
113
+ [group, options]
100
114
  end
101
115
  end
102
116
 
103
- def parse_queue(queue, weight = nil, group)
117
+ def parse_queue(queue, weight, group)
104
118
  Shoryuken.add_queue(queue, [weight.to_i, 1].max, group)
105
119
  end
106
120
 
@@ -155,7 +169,7 @@ module Shoryuken
155
169
  end
156
170
 
157
171
  def validate_workers
158
- return if defined?(::ActiveJob)
172
+ return if Shoryuken.active_job?
159
173
 
160
174
  all_queues = Shoryuken.ungrouped_queues
161
175
  queues_with_workers = Shoryuken.worker_registry.queues
@@ -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
- started_at = Time.now
12
+ fetch_with_auto_retry(3) do
13
+ started_at = Time.now
15
14
 
16
- logger.debug { "Looking for new messages in #{queue}" }
15
+ logger.debug { "Looking for new messages in #{queue}" }
17
16
 
18
- sqs_msgs = Array(receive_messages(queue, [FETCH_LIMIT, limit].min))
17
+ sqs_msgs = Array(receive_messages(queue, [FETCH_LIMIT, limit].min))
19
18
 
20
- logger.info { "Found #{sqs_msgs.size} messages for #{queue.name}" } unless sqs_msgs.empty?
21
- logger.debug { "Fetcher for #{queue} completed in #{elapsed(started_at)} ms" }
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
- sqs_msgs
22
+ sqs_msgs
23
+ end
24
24
  end
25
25
 
26
26
  private
27
27
 
28
- def receive_messages(queue, limit)
29
- # AWS limits the batch size by 10
30
- limit = limit > FETCH_LIMIT ? FETCH_LIMIT : limit
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
- options = Shoryuken.sqs_client_receive_message_opts[group].to_h.dup
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
@@ -3,8 +3,7 @@ module Shoryuken
3
3
  include Util
4
4
 
5
5
  def initialize
6
- @managers = create_managers
7
- @shutdowning = Concurrent::AtomicBoolean.new(false)
6
+ @managers = create_managers
8
7
  end
9
8
 
10
9
  def start
@@ -41,29 +40,13 @@ module Shoryuken
41
40
 
42
41
  def start_managers
43
42
  @managers.each do |manager|
44
- Concurrent::Promise.execute { manager.start }.rescue do |ex|
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
 
65
- @managers.each(&:stop)
66
-
67
50
  stop_callback
68
51
  end
69
52
 
@@ -90,7 +73,8 @@ module Shoryuken
90
73
  Shoryuken::Manager.new(
91
74
  Shoryuken::Fetcher.new(group),
92
75
  Shoryuken.polling_strategy(group).new(options[:queues]),
93
- options[:concurrency]
76
+ options[:concurrency],
77
+ executor
94
78
  )
95
79
  end
96
80
  end
@@ -3,7 +3,6 @@ require 'logger'
3
3
 
4
4
  module Shoryuken
5
5
  module Logging
6
-
7
6
  class Pretty < Logger::Formatter
8
7
  # Provide a call() method that returns the formatted message.
9
8
  def call(severity, time, program_name, message)
@@ -37,9 +36,5 @@ module Shoryuken
37
36
  def self.logger=(log)
38
37
  @logger = (log ? log : Logger.new('/dev/null'))
39
38
  end
40
-
41
- def logger
42
- shoryuken::Logging.logger
43
- end
44
39
  end
45
40
  end
@@ -6,47 +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
- def initialize(fetcher, polling_strategy, concurrency)
9
+ def initialize(fetcher, polling_strategy, concurrency, executor)
10
10
  @fetcher = fetcher
11
11
  @polling_strategy = polling_strategy
12
12
  @max_processors = concurrency
13
13
  @busy_processors = Concurrent::AtomicFixnum.new(0)
14
- @done = Concurrent::AtomicBoolean.new(false)
14
+ @executor = executor
15
+ @running = Concurrent::AtomicBoolean.new(true)
15
16
  end
16
17
 
17
18
  def start
18
- dispatch
19
+ dispatch_loop
19
20
  end
20
21
 
21
- def stop
22
- @done.make_true
22
+ private
23
+
24
+ def running?
25
+ @running.true? && @executor.running?
23
26
  end
24
27
 
25
- private
28
+ def dispatch_loop
29
+ return unless running?
26
30
 
27
- def stopped?
28
- @done.true? || !Concurrent.global_io_executor.running?
31
+ @executor.post { dispatch }
29
32
  end
30
33
 
31
34
  def dispatch
32
- return if stopped?
35
+ return unless running?
33
36
 
34
- if !ready.positive? || (queue = @polling_strategy.next_queue).nil?
35
- return dispatch_later
37
+ if ready <= 0 || (queue = @polling_strategy.next_queue).nil?
38
+ return sleep(MIN_DISPATCH_INTERVAL)
36
39
  end
37
40
 
38
- fire_event(:dispatch)
41
+ fire_event(:dispatch, false, queue_name: queue.name)
39
42
 
40
- logger.info { "Ready: #{ready}, Busy: #{busy}, Active Queues: #{@polling_strategy.active_queues}" }
43
+ logger.debug { "Ready: #{ready}, Busy: #{busy}, Active Queues: #{@polling_strategy.active_queues}" }
41
44
 
42
45
  batched_queue?(queue) ? dispatch_batch(queue) : dispatch_single_messages(queue)
43
-
44
- dispatch
45
- end
46
-
47
- def dispatch_later
48
- sleep(MIN_DISPATCH_INTERVAL)
49
- dispatch
46
+ rescue => ex
47
+ handle_dispatch_error(ex)
48
+ ensure
49
+ dispatch_loop
50
50
  end
51
51
 
52
52
  def busy
@@ -62,15 +62,15 @@ module Shoryuken
62
62
  end
63
63
 
64
64
  def assign(queue_name, sqs_msg)
65
- return if stopped?
65
+ return unless running?
66
66
 
67
67
  logger.debug { "Assigning #{sqs_msg.message_id}" }
68
68
 
69
69
  @busy_processors.increment
70
70
 
71
- Concurrent::Promise.execute {
72
- Processor.new(queue_name, sqs_msg).process
73
- }.then { processor_done }.rescue { processor_done }
71
+ Concurrent::Promise.execute(
72
+ executor: @executor
73
+ ) { Processor.process(queue_name, sqs_msg) }.then { processor_done }.rescue { processor_done }
74
74
  end
75
75
 
76
76
  def dispatch_batch(queue)
@@ -99,5 +99,14 @@ module Shoryuken
99
99
 
100
100
  sqs_msgs
101
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
102
111
  end
103
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 #{worker_name(worker.class, sqs_msg, body)}/#{queue}/#{sqs_msg.message_id} " \
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
- 'Could not auto extend the message ' \
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
- Shoryuken::Logging.with_context("#{worker_name(worker.class, sqs_msg, body)}/#{queue}/#{sqs_msg.message_id}") do
9
- begin
10
- started_at = Time.now
8
+ begin
9
+ started_at = Time.now
11
10
 
12
- logger.info { "started at #{started_at}" }
11
+ logger.info { "started at #{started_at}" }
13
12
 
14
- yield
13
+ yield
15
14
 
16
- total_time = elapsed(started_at)
15
+ total_time = elapsed(started_at)
17
16
 
18
- if (total_time / 1000.0) > (timeout = Shoryuken::Client.queues(queue).visibility_timeout)
19
- logger.warn { "exceeded the queue visibility timeout by #{total_time - (timeout * 1000)} ms" }
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