shoryuken 6.2.1 → 7.0.0.alpha2

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 (119) hide show
  1. checksums.yaml +4 -4
  2. data/.devcontainer/base.Dockerfile +1 -1
  3. data/.github/workflows/push.yml +36 -0
  4. data/.github/workflows/specs.yml +40 -30
  5. data/.github/workflows/verify-action-pins.yml +16 -0
  6. data/.gitignore +2 -1
  7. data/.rspec +2 -1
  8. data/.rubocop.yml +6 -1
  9. data/.ruby-version +1 -0
  10. data/Appraisals +8 -27
  11. data/CHANGELOG.md +213 -139
  12. data/Gemfile +2 -7
  13. data/README.md +14 -26
  14. data/Rakefile +2 -0
  15. data/bin/cli/base.rb +1 -2
  16. data/bin/cli/sqs.rb +13 -5
  17. data/bin/shoryuken +2 -1
  18. data/docker-compose.yml +22 -0
  19. data/gemfiles/rails_7_0.gemfile +10 -13
  20. data/gemfiles/rails_7_1.gemfile +19 -0
  21. data/gemfiles/rails_7_2.gemfile +19 -0
  22. data/gemfiles/rails_8_0.gemfile +19 -0
  23. data/lib/shoryuken/body_parser.rb +3 -1
  24. data/lib/shoryuken/client.rb +2 -0
  25. data/lib/shoryuken/default_exception_handler.rb +2 -0
  26. data/lib/shoryuken/default_worker_registry.rb +11 -11
  27. data/lib/shoryuken/environment_loader.rb +6 -6
  28. data/lib/shoryuken/extensions/active_job_adapter.rb +13 -6
  29. data/lib/shoryuken/extensions/active_job_concurrent_send_adapter.rb +5 -5
  30. data/lib/shoryuken/extensions/active_job_extensions.rb +2 -0
  31. data/lib/shoryuken/fetcher.rb +4 -2
  32. data/lib/shoryuken/helpers/atomic_boolean.rb +44 -0
  33. data/lib/shoryuken/helpers/atomic_counter.rb +104 -0
  34. data/lib/shoryuken/helpers/atomic_hash.rb +182 -0
  35. data/lib/shoryuken/helpers/hash_utils.rb +56 -0
  36. data/lib/shoryuken/helpers/string_utils.rb +65 -0
  37. data/lib/shoryuken/inline_message.rb +22 -0
  38. data/lib/shoryuken/launcher.rb +2 -0
  39. data/lib/shoryuken/logging.rb +19 -5
  40. data/lib/shoryuken/manager.rb +15 -5
  41. data/lib/shoryuken/message.rb +2 -0
  42. data/lib/shoryuken/middleware/chain.rb +2 -0
  43. data/lib/shoryuken/middleware/server/active_record.rb +2 -0
  44. data/lib/shoryuken/middleware/server/auto_delete.rb +2 -0
  45. data/lib/shoryuken/middleware/server/auto_extend_visibility.rb +10 -10
  46. data/lib/shoryuken/middleware/server/exponential_backoff_retry.rb +5 -3
  47. data/lib/shoryuken/middleware/server/timing.rb +2 -0
  48. data/lib/shoryuken/options.rb +14 -5
  49. data/lib/shoryuken/polling/base_strategy.rb +126 -0
  50. data/lib/shoryuken/polling/queue_configuration.rb +103 -0
  51. data/lib/shoryuken/polling/strict_priority.rb +2 -0
  52. data/lib/shoryuken/polling/weighted_round_robin.rb +2 -0
  53. data/lib/shoryuken/processor.rb +5 -2
  54. data/lib/shoryuken/queue.rb +6 -4
  55. data/lib/shoryuken/runner.rb +9 -12
  56. data/lib/shoryuken/util.rb +6 -6
  57. data/lib/shoryuken/version.rb +3 -1
  58. data/lib/shoryuken/worker/default_executor.rb +2 -0
  59. data/lib/shoryuken/worker/inline_executor.rb +9 -2
  60. data/lib/shoryuken/worker.rb +2 -0
  61. data/lib/shoryuken/worker_registry.rb +2 -0
  62. data/lib/shoryuken.rb +11 -34
  63. data/renovate.json +16 -0
  64. data/shoryuken.gemspec +7 -4
  65. data/spec/integration/launcher_spec.rb +3 -4
  66. data/spec/shared_examples_for_active_job.rb +13 -8
  67. data/spec/shoryuken/body_parser_spec.rb +2 -4
  68. data/spec/shoryuken/client_spec.rb +1 -1
  69. data/spec/shoryuken/default_exception_handler_spec.rb +9 -10
  70. data/spec/shoryuken/default_worker_registry_spec.rb +1 -2
  71. data/spec/shoryuken/environment_loader_spec.rb +9 -8
  72. data/spec/shoryuken/extensions/active_job_adapter_spec.rb +2 -1
  73. data/spec/shoryuken/extensions/active_job_base_spec.rb +2 -1
  74. data/spec/shoryuken/extensions/active_job_concurrent_send_adapter_spec.rb +2 -1
  75. data/spec/shoryuken/extensions/active_job_wrapper_spec.rb +2 -1
  76. data/spec/shoryuken/fetcher_spec.rb +23 -26
  77. data/spec/shoryuken/helpers/atomic_boolean_spec.rb +196 -0
  78. data/spec/shoryuken/helpers/atomic_counter_spec.rb +177 -0
  79. data/spec/shoryuken/helpers/atomic_hash_spec.rb +307 -0
  80. data/spec/shoryuken/helpers/hash_utils_spec.rb +145 -0
  81. data/spec/shoryuken/helpers/string_utils_spec.rb +124 -0
  82. data/spec/shoryuken/helpers_integration_spec.rb +96 -0
  83. data/spec/shoryuken/inline_message_spec.rb +196 -0
  84. data/spec/shoryuken/launcher_spec.rb +1 -2
  85. data/spec/shoryuken/manager_spec.rb +1 -2
  86. data/spec/shoryuken/middleware/chain_spec.rb +1 -1
  87. data/spec/shoryuken/middleware/server/auto_delete_spec.rb +1 -1
  88. data/spec/shoryuken/middleware/server/auto_extend_visibility_spec.rb +1 -1
  89. data/spec/shoryuken/middleware/server/exponential_backoff_retry_spec.rb +1 -1
  90. data/spec/shoryuken/middleware/server/timing_spec.rb +1 -1
  91. data/spec/shoryuken/options_spec.rb +4 -4
  92. data/spec/shoryuken/polling/base_strategy_spec.rb +280 -0
  93. data/spec/shoryuken/polling/queue_configuration_spec.rb +195 -0
  94. data/spec/shoryuken/polling/strict_priority_spec.rb +1 -1
  95. data/spec/shoryuken/polling/weighted_round_robin_spec.rb +1 -1
  96. data/spec/shoryuken/processor_spec.rb +1 -1
  97. data/spec/shoryuken/queue_spec.rb +2 -3
  98. data/spec/shoryuken/runner_spec.rb +1 -3
  99. data/spec/shoryuken/util_spec.rb +1 -1
  100. data/spec/shoryuken/worker/default_executor_spec.rb +1 -1
  101. data/spec/shoryuken/worker/inline_executor_spec.rb +57 -1
  102. data/spec/shoryuken/worker_spec.rb +15 -11
  103. data/spec/shoryuken_spec.rb +1 -1
  104. data/spec/spec_helper.rb +19 -4
  105. metadata +79 -35
  106. data/.codeclimate.yml +0 -20
  107. data/.github/FUNDING.yml +0 -12
  108. data/.github/dependabot.yml +0 -6
  109. data/.github/workflows/stale.yml +0 -20
  110. data/.reek.yml +0 -5
  111. data/gemfiles/aws_sdk_core_2.gemfile +0 -21
  112. data/gemfiles/rails_4_2.gemfile +0 -20
  113. data/gemfiles/rails_5_2.gemfile +0 -21
  114. data/gemfiles/rails_6_0.gemfile +0 -21
  115. data/gemfiles/rails_6_1.gemfile +0 -21
  116. data/lib/shoryuken/core_ext.rb +0 -69
  117. data/lib/shoryuken/polling/base.rb +0 -67
  118. data/shoryuken.jpg +0 -0
  119. data/spec/shoryuken/core_ext_spec.rb +0 -40
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shoryuken
4
+ module Polling
5
+ # Abstract base class for queue polling strategies.
6
+ #
7
+ # This class defines the interface that all polling strategies must implement
8
+ # to manage queue selection and message flow control in Shoryuken workers.
9
+ # Polling strategies determine which queue to fetch messages from next and
10
+ # how to handle scenarios where queues have no messages available.
11
+ #
12
+ # @abstract Subclass and override {#next_queue}, {#messages_found}, and {#active_queues}
13
+ # to implement a custom polling strategy.
14
+ #
15
+ # @example Implementing a custom polling strategy
16
+ # class CustomStrategy < BaseStrategy
17
+ # def initialize(queues)
18
+ # @queues = queues
19
+ # end
20
+ #
21
+ # def next_queue
22
+ # # Return next queue to poll
23
+ # @queues.sample
24
+ # end
25
+ #
26
+ # def messages_found(queue, count)
27
+ # # Handle result of polling
28
+ # logger.info "Found #{count} messages in #{queue}"
29
+ # end
30
+ #
31
+ # def active_queues
32
+ # # Return list of active queues
33
+ # @queues
34
+ # end
35
+ # end
36
+ #
37
+ # @see WeightedRoundRobin
38
+ # @see StrictPriority
39
+ class BaseStrategy
40
+ include Util
41
+
42
+ # Returns the next queue to poll for messages.
43
+ #
44
+ # This method should return a QueueConfiguration object representing
45
+ # the next queue that should be polled for messages, or nil if no
46
+ # queues are currently available for polling.
47
+ #
48
+ # @abstract Subclasses must implement this method
49
+ # @return [QueueConfiguration, nil] Next queue to poll, or nil if none available
50
+ # @raise [NotImplementedError] if not implemented by subclass
51
+ def next_queue
52
+ fail NotImplementedError
53
+ end
54
+
55
+ # Called when messages are found (or not found) in a queue.
56
+ #
57
+ # This method is invoked after polling a queue to inform the strategy
58
+ # about the number of messages that were retrieved. Strategies can use
59
+ # this information to make decisions about future polling behavior,
60
+ # such as pausing empty queues or adjusting queue weights.
61
+ #
62
+ # @abstract Subclasses must implement this method
63
+ # @param _queue [String] The name of the queue that was polled
64
+ # @param _messages_found [Integer] The number of messages retrieved
65
+ # @raise [NotImplementedError] if not implemented by subclass
66
+ def messages_found(_queue, _messages_found)
67
+ fail NotImplementedError
68
+ end
69
+
70
+ # Called when a message from a queue has been processed.
71
+ #
72
+ # This optional callback is invoked after a message has been successfully
73
+ # processed by a worker. Strategies can use this information for cleanup
74
+ # or to adjust their polling behavior.
75
+ #
76
+ # @param _queue [String] The name of the queue whose message was processed
77
+ # @return [void]
78
+ def message_processed(_queue); end
79
+
80
+ # Returns the list of currently active queues.
81
+ #
82
+ # This method should return an array representing the queues that are
83
+ # currently active and available for polling. The format may vary by
84
+ # strategy implementation.
85
+ #
86
+ # @abstract Subclasses must implement this method
87
+ # @return [Array] List of active queues
88
+ # @raise [NotImplementedError] if not implemented by subclass
89
+ def active_queues
90
+ fail NotImplementedError
91
+ end
92
+
93
+ # Compares this strategy with another object for equality.
94
+ #
95
+ # Two strategies are considered equal if they have the same active queues.
96
+ # This method also supports comparison with Array objects for backward
97
+ # compatibility.
98
+ #
99
+ # @param other [Object] Object to compare with
100
+ # @return [Boolean] true if strategies are equivalent
101
+ def ==(other)
102
+ case other
103
+ when Array
104
+ @queues == other
105
+ else
106
+ if other.respond_to?(:active_queues)
107
+ active_queues == other.active_queues
108
+ else
109
+ false
110
+ end
111
+ end
112
+ end
113
+
114
+ # Returns the delay time for pausing empty queues.
115
+ #
116
+ # This method returns the amount of time (in seconds) that empty queues
117
+ # should be paused before being polled again. The delay can be set at
118
+ # the strategy level or falls back to the global Shoryuken delay setting.
119
+ #
120
+ # @return [Float] Delay time in seconds
121
+ def delay
122
+ @delay || Shoryuken.options[:delay].to_f
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shoryuken
4
+ module Polling
5
+ # Configuration object representing a queue and its associated options.
6
+ #
7
+ # This class encapsulates a queue name along with any polling-specific
8
+ # options or metadata. It provides a structured way to pass queue
9
+ # information between polling strategies and the message fetching system.
10
+ #
11
+ # The class extends Struct to provide attribute accessors for name and options
12
+ # while adding custom behavior for equality comparison and string representation.
13
+ #
14
+ # @example Creating a basic queue configuration
15
+ # config = QueueConfiguration.new('my_queue', {})
16
+ # config.name # => 'my_queue'
17
+ # config.options # => {}
18
+ #
19
+ # @example Creating a queue configuration with options
20
+ # config = QueueConfiguration.new('priority_queue', { priority: :high })
21
+ # config.name # => 'priority_queue'
22
+ # config.options # => { priority: :high }
23
+ #
24
+ # @example Comparing configurations
25
+ # config1 = QueueConfiguration.new('queue', {})
26
+ # config2 = QueueConfiguration.new('queue', {})
27
+ # config1 == config2 # => true
28
+ # config1 == 'queue' # => true (when options are empty)
29
+ #
30
+ # @attr_reader [String] name The name of the queue
31
+ # @attr_reader [Hash] options Additional options or metadata for the queue
32
+ QueueConfiguration = Struct.new(:name, :options) do
33
+ # Generates a hash value based on the queue name.
34
+ #
35
+ # This method ensures that QueueConfiguration objects can be used
36
+ # as hash keys and that configurations with the same queue name
37
+ # will have the same hash value regardless of their options.
38
+ #
39
+ # @return [Integer] Hash value based on the queue name
40
+ def hash
41
+ name.hash
42
+ end
43
+
44
+ # Compares this configuration with another object for equality.
45
+ #
46
+ # Two QueueConfiguration objects are equal if they have the same name
47
+ # and options. For convenience, a configuration with empty options can
48
+ # also be compared directly with a string queue name.
49
+ #
50
+ # @param other [Object] The object to compare with
51
+ # @return [Boolean] true if the objects are considered equal
52
+ #
53
+ # @example Comparing with another QueueConfiguration
54
+ # config1 = QueueConfiguration.new('queue', {})
55
+ # config2 = QueueConfiguration.new('queue', {})
56
+ # config1 == config2 # => true
57
+ #
58
+ # @example Comparing with a string (only when options are empty)
59
+ # config = QueueConfiguration.new('queue', {})
60
+ # config == 'queue' # => true
61
+ #
62
+ # config_with_options = QueueConfiguration.new('queue', { weight: 5 })
63
+ # config_with_options == 'queue' # => false
64
+ def ==(other)
65
+ case other
66
+ when String
67
+ if options.empty?
68
+ name == other
69
+ else
70
+ false
71
+ end
72
+ else
73
+ super
74
+ end
75
+ end
76
+
77
+ alias_method :eql?, :==
78
+
79
+ # Returns a string representation of the queue configuration.
80
+ #
81
+ # For configurations with empty options, returns just the queue name.
82
+ # For configurations with options, returns a detailed representation
83
+ # showing both the name and the options hash.
84
+ #
85
+ # @return [String] String representation of the configuration
86
+ #
87
+ # @example Simple queue without options
88
+ # config = QueueConfiguration.new('simple_queue', {})
89
+ # config.to_s # => 'simple_queue'
90
+ #
91
+ # @example Queue with options
92
+ # config = QueueConfiguration.new('complex_queue', { priority: :high })
93
+ # config.to_s # => '#<QueueConfiguration complex_queue options={:priority=>:high}>'
94
+ def to_s
95
+ if options&.empty?
96
+ name
97
+ else
98
+ "#<QueueConfiguration #{name} options=#{options.inspect}>"
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Shoryuken
2
4
  module Polling
3
5
  class StrictPriority < BaseStrategy
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Shoryuken
2
4
  module Polling
3
5
  class WeightedRoundRobin < BaseStrategy
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Shoryuken
2
4
  class Processor
3
5
  include Util
@@ -16,6 +18,7 @@ module Shoryuken
16
18
  def process
17
19
  worker_perform = proc do
18
20
  return logger.error { "No worker found for #{queue}" } unless worker
21
+
19
22
  Shoryuken::Logging.with_context("#{worker_name(worker.class, sqs_msg, body)}/#{queue}/#{sqs_msg.message_id}") do
20
23
  worker.class.server_middleware.invoke(worker, queue, sqs_msg, body) do
21
24
  worker.perform(sqs_msg, body)
@@ -30,8 +33,8 @@ module Shoryuken
30
33
  else
31
34
  worker_perform.call
32
35
  end
33
- rescue Exception => ex
34
- Array(Shoryuken.exception_handlers).each { |handler| handler.call(ex, queue, sqs_msg) }
36
+ rescue Exception => e
37
+ Array(Shoryuken.exception_handlers).each { |handler| handler.call(e, queue, sqs_msg) }
35
38
 
36
39
  raise
37
40
  end
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Shoryuken
2
4
  class Queue
3
5
  include Util
4
6
 
5
- FIFO_ATTR = 'FifoQueue'.freeze
6
- MESSAGE_GROUP_ID = 'ShoryukenMessage'.freeze
7
- VISIBILITY_TIMEOUT_ATTR = 'VisibilityTimeout'.freeze
7
+ FIFO_ATTR = 'FifoQueue'
8
+ MESSAGE_GROUP_ID = 'ShoryukenMessage'
9
+ VISIBILITY_TIMEOUT_ATTR = 'VisibilityTimeout'
8
10
 
9
11
  attr_accessor :name, :client, :url
10
12
 
@@ -50,7 +52,7 @@ module Shoryuken
50
52
 
51
53
  def fifo?
52
54
  # Make sure the memoization work with boolean to avoid multiple calls to SQS
53
- # see https://github.com/phstc/shoryuken/pull/529
55
+ # see https://github.com/ruby-shoryuken/shoryuken/pull/529
54
56
  return @_fifo if defined?(@_fifo)
55
57
 
56
58
  @_fifo = queue_attributes.attributes[FIFO_ATTR] == 'true'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  $stdout.sync = true
2
4
 
3
5
  require 'singleton'
@@ -7,7 +9,6 @@ require 'erb'
7
9
  require 'shoryuken'
8
10
 
9
11
  module Shoryuken
10
- # rubocop:disable Lint/InheritException
11
12
  # See: https://github.com/mperham/sidekiq/blob/33f5d6b2b6c0dfaab11e5d39688cab7ebadc83ae/lib/sidekiq/cli.rb#L20
12
13
  class Shutdown < Interrupt; end
13
14
 
@@ -19,13 +20,11 @@ module Shoryuken
19
20
  self_read, self_write = IO.pipe
20
21
 
21
22
  %w[INT TERM USR1 TSTP TTIN].each do |sig|
22
- begin
23
- trap sig do
24
- self_write.puts(sig)
25
- end
26
- rescue ArgumentError
27
- puts "Signal #{sig} not supported"
23
+ trap sig do
24
+ self_write.puts(sig)
28
25
  end
26
+ rescue ArgumentError
27
+ puts "Signal #{sig} not supported"
29
28
  end
30
29
 
31
30
  loader = EnvironmentLoader.setup_options(options)
@@ -77,11 +76,9 @@ module Shoryuken
77
76
  Process.daemon(true, true)
78
77
 
79
78
  files_to_reopen.each do |file|
80
- begin
81
- file.reopen file.path, 'a+'
82
- file.sync = true
83
- rescue ::Exception
84
- end
79
+ file.reopen file.path, 'a+'
80
+ file.sync = true
81
+ rescue ::Exception
85
82
  end
86
83
 
87
84
  [$stdout, $stderr].each do |io|
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Shoryuken
2
4
  module Util
3
5
  def logger
@@ -9,12 +11,10 @@ module Shoryuken
9
11
  arr = Shoryuken.options[:lifecycle_events][event]
10
12
  arr.reverse! if reverse
11
13
  arr.each do |block|
12
- begin
13
- block.call(event_options)
14
- rescue => ex
15
- logger.warn(event: event)
16
- logger.warn "#{ex.class.name}: #{ex.message}"
17
- end
14
+ block.call(event_options)
15
+ rescue => e
16
+ logger.warn(event: event)
17
+ logger.warn "#{e.class.name}: #{e.message}"
18
18
  end
19
19
  end
20
20
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Shoryuken
2
- VERSION = '6.2.1'.freeze
4
+ VERSION = '7.0.0.alpha2'
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Shoryuken
2
4
  module Worker
3
5
  class DefaultExecutor
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Shoryuken
2
4
  module Worker
3
5
  class InlineExecutor
@@ -5,13 +7,18 @@ module Shoryuken
5
7
  def perform_async(worker_class, body, options = {})
6
8
  body = JSON.dump(body) if body.is_a?(Hash)
7
9
  queue_name = options.delete(:queue) || worker_class.get_shoryuken_options['queue']
10
+ message_attributes = options.delete(:message_attributes) || {}
11
+ message_attributes['shoryuken_class'] = {
12
+ string_value: worker_class.to_s,
13
+ data_type: 'String'
14
+ }
8
15
 
9
- sqs_msg = OpenStruct.new(
16
+ sqs_msg = InlineMessage.new(
10
17
  body: body,
11
18
  attributes: nil,
12
19
  md5_of_body: nil,
13
20
  md5_of_message_attributes: nil,
14
- message_attributes: nil,
21
+ message_attributes: message_attributes,
15
22
  message_id: nil,
16
23
  receipt_handle: nil,
17
24
  delete: nil,
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Shoryuken
2
4
  module Worker
3
5
  def self.included(base)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Shoryuken
2
4
  class WorkerRegistry
3
5
  def batch_receive_messages?(_queue)
data/lib/shoryuken.rb CHANGED
@@ -1,43 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'yaml'
2
4
  require 'json'
3
- require 'aws-sdk-core'
4
- begin
5
- require 'aws-sdk-sqs' unless defined?(Aws::SQS)
6
- rescue LoadError
7
- fail "AWS SDK 3 requires aws-sdk-sqs to be installed separately. Please add gem 'aws-sdk-sqs' to your Gemfile"
8
- end
5
+ require 'aws-sdk-sqs'
9
6
  require 'time'
10
7
  require 'concurrent'
11
8
  require 'forwardable'
9
+ require 'zeitwerk'
12
10
 
13
- require 'shoryuken/version'
14
- require 'shoryuken/core_ext'
15
- require 'shoryuken/util'
16
- require 'shoryuken/logging'
17
- require 'shoryuken/environment_loader'
18
- require 'shoryuken/queue'
19
- require 'shoryuken/message'
20
- require 'shoryuken/client'
21
- require 'shoryuken/worker'
22
- require 'shoryuken/worker/default_executor'
23
- require 'shoryuken/worker/inline_executor'
24
- require 'shoryuken/worker_registry'
25
- require 'shoryuken/default_worker_registry'
26
- require 'shoryuken/default_exception_handler'
27
- require 'shoryuken/middleware/chain'
28
- require 'shoryuken/middleware/server/auto_delete'
29
- Shoryuken::Middleware::Server.autoload :AutoExtendVisibility, 'shoryuken/middleware/server/auto_extend_visibility'
30
- require 'shoryuken/middleware/server/exponential_backoff_retry'
31
- require 'shoryuken/middleware/server/timing'
32
- require 'shoryuken/polling/base'
33
- require 'shoryuken/polling/weighted_round_robin'
34
- require 'shoryuken/polling/strict_priority'
35
- require 'shoryuken/manager'
36
- require 'shoryuken/launcher'
37
- require 'shoryuken/processor'
38
- require 'shoryuken/body_parser'
39
- require 'shoryuken/fetcher'
40
- require 'shoryuken/options'
11
+ # Set up Zeitwerk loader
12
+ loader = Zeitwerk::Loader.for_gem
13
+ loader.ignore("#{__dir__}/shoryuken/extensions")
14
+ loader.setup
41
15
 
42
16
  module Shoryuken
43
17
  extend SingleForwardable
@@ -57,6 +31,8 @@ module Shoryuken
57
31
  :groups,
58
32
  :add_queue,
59
33
  :ungrouped_queues,
34
+ :thread_priority,
35
+ :thread_priority=,
60
36
  :worker_registry,
61
37
  :worker_registry=,
62
38
  :worker_executor,
@@ -78,6 +54,7 @@ module Shoryuken
78
54
  :exception_handlers=,
79
55
  :options,
80
56
  :logger,
57
+ :logger=,
81
58
  :register_worker,
82
59
  :configure_server,
83
60
  :server?,
data/renovate.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3
+ "extends": [
4
+ "config:recommended"
5
+ ],
6
+ "github-actions": {
7
+ "enabled": true,
8
+ "pinDigests": true
9
+ },
10
+ "packageRules": [
11
+ {
12
+ "matchManagers": ["github-actions"],
13
+ "minimumReleaseAge": "7 days"
14
+ }
15
+ ]
16
+ }
data/shoryuken.gemspec CHANGED
@@ -1,4 +1,3 @@
1
-
2
1
  lib = File.expand_path('lib', __dir__)
3
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
3
  require 'shoryuken/version'
@@ -17,11 +16,15 @@ Gem::Specification.new do |spec|
17
16
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
17
  spec.require_paths = ['lib']
19
18
 
19
+ spec.add_dependency 'aws-sdk-sqs', '>= 1.66.0'
20
+ spec.add_dependency 'concurrent-ruby'
21
+ spec.add_dependency 'thor'
22
+ spec.add_dependency 'zeitwerk', '~> 2.6'
23
+
20
24
  spec.add_development_dependency 'dotenv'
25
+ spec.add_development_dependency 'ostruct'
21
26
  spec.add_development_dependency 'rake'
22
27
  spec.add_development_dependency 'rspec'
23
28
 
24
- spec.add_dependency 'aws-sdk-core', '>= 2'
25
- spec.add_dependency 'concurrent-ruby'
26
- spec.add_dependency 'thor'
29
+ spec.required_ruby_version = '>= 3.1.0'
27
30
  end
@@ -1,13 +1,12 @@
1
- require 'spec_helper'
2
- require 'shoryuken/manager'
3
- require 'shoryuken/launcher'
1
+ # frozen_string_literal: true
2
+
4
3
  require 'securerandom'
5
4
 
6
5
  RSpec.describe Shoryuken::Launcher do
7
6
  let(:sqs_client) do
8
7
  Aws::SQS::Client.new(
9
8
  region: 'us-east-1',
10
- endpoint: 'http://localhost:5000',
9
+ endpoint: 'http://localhost:4566',
11
10
  access_key_id: 'fake',
12
11
  secret_access_key: 'fake'
13
12
  )
@@ -24,7 +24,7 @@ RSpec.shared_examples 'active_job_adapters' do
24
24
  expect(queue).to receive(:send_message) do |hash|
25
25
  expect(hash[:message_deduplication_id]).to_not be
26
26
  expect(hash[:message_attributes]['shoryuken_class'][:string_value]).to eq(described_class::JobWrapper.to_s)
27
- expect(hash[:message_attributes]['shoryuken_class'][:data_type]).to eq("String")
27
+ expect(hash[:message_attributes]['shoryuken_class'][:data_type]).to eq('String')
28
28
  expect(hash[:message_attributes].keys).to eq(['shoryuken_class'])
29
29
  end
30
30
  expect(Shoryuken).to receive(:register_worker).with(job.queue_name, described_class::JobWrapper)
@@ -133,9 +133,9 @@ RSpec.shared_examples 'active_job_adapters' do
133
133
 
134
134
  expect(queue).to receive(:send_message) do |hash|
135
135
  expect(hash[:message_attributes]['shoryuken_class'][:string_value]).to eq(described_class::JobWrapper.to_s)
136
- expect(hash[:message_attributes]['shoryuken_class'][:data_type]).to eq("String")
136
+ expect(hash[:message_attributes]['shoryuken_class'][:data_type]).to eq('String')
137
137
  expect(hash[:message_attributes]['tracer_id'][:string_value]).to eq(custom_message_attributes['tracer_id'][:string_value])
138
- expect(hash[:message_attributes]['tracer_id'][:data_type]).to eq("String")
138
+ expect(hash[:message_attributes]['tracer_id'][:data_type]).to eq('String')
139
139
  end
140
140
  expect(Shoryuken).to receive(:register_worker).with(job.queue_name, described_class::JobWrapper)
141
141
 
@@ -157,7 +157,8 @@ RSpec.shared_examples 'active_job_adapters' do
157
157
  it 'should enqueue a message with the message_attributes specified on the job' do
158
158
  expect(queue).to receive(:send_message) do |hash|
159
159
  expect(hash[:message_attributes]['tracer_id']).to eq({ data_type: 'String', string_value: 'job-value' })
160
- expect(hash[:message_attributes]['shoryuken_class']).to eq({ data_type: 'String', string_value: described_class::JobWrapper.to_s })
160
+ expect(hash[:message_attributes]['shoryuken_class']).to eq({ data_type: 'String',
161
+ string_value: described_class::JobWrapper.to_s })
161
162
  end
162
163
  subject.enqueue job
163
164
  end
@@ -185,8 +186,10 @@ RSpec.shared_examples 'active_job_adapters' do
185
186
 
186
187
  expect(queue).to receive(:send_message) do |hash|
187
188
  expect(hash[:message_attributes]['tracer_id']).to be_nil
188
- expect(hash[:message_attributes]['options_tracer_id']).to eq({ data_type: 'String', string_value: 'options-value' })
189
- expect(hash[:message_attributes]['shoryuken_class']).to eq({ data_type: 'String', string_value: described_class::JobWrapper.to_s })
189
+ expect(hash[:message_attributes]['options_tracer_id']).to eq({ data_type: 'String',
190
+ string_value: 'options-value' })
191
+ expect(hash[:message_attributes]['shoryuken_class']).to eq({ data_type: 'String',
192
+ string_value: described_class::JobWrapper.to_s })
190
193
  end
191
194
  subject.enqueue job, message_attributes: custom_message_attributes
192
195
  end
@@ -225,7 +228,8 @@ RSpec.shared_examples 'active_job_adapters' do
225
228
 
226
229
  it 'should enqueue a message with the message_system_attributes specified on the job' do
227
230
  expect(queue).to receive(:send_message) do |hash|
228
- expect(hash[:message_system_attributes]['AWSTraceHeader']).to eq({ data_type: 'String', string_value: 'job-value' })
231
+ expect(hash[:message_system_attributes]['AWSTraceHeader']).to eq({ data_type: 'String',
232
+ string_value: 'job-value' })
229
233
  end
230
234
  subject.enqueue job
231
235
  end
@@ -253,7 +257,8 @@ RSpec.shared_examples 'active_job_adapters' do
253
257
 
254
258
  expect(queue).to receive(:send_message) do |hash|
255
259
  expect(hash[:message_system_attributes]['job_trace_header']).to be_nil
256
- expect(hash[:message_system_attributes]['options_trace_header']).to eq({ data_type: 'String', string_value: 'options-value' })
260
+ expect(hash[:message_system_attributes]['options_trace_header']).to eq({ data_type: 'String',
261
+ string_value: 'options-value' })
257
262
  end
258
263
  subject.enqueue job, message_system_attributes: custom_message_attributes
259
264
  end
@@ -1,5 +1,4 @@
1
- require 'spec_helper'
2
- require 'shoryuken/body_parser'
1
+ # frozen_string_literal: true
3
2
 
4
3
  RSpec.describe Shoryuken::BodyParser do
5
4
  let(:sqs_msg) { double }
@@ -69,8 +68,7 @@ RSpec.describe Shoryuken::BodyParser do
69
68
  end
70
69
 
71
70
  specify do
72
- expect { described_class.parse(TestWorker, sqs_msg) }
73
- .to raise_error(JSON::ParserError, /unexpected token at 'invalid JSON'/)
71
+ expect { described_class.parse(TestWorker, sqs_msg) }.to raise_error(JSON::ParserError)
74
72
  end
75
73
  end
76
74
 
@@ -1,4 +1,4 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
2
 
3
3
  RSpec.describe Shoryuken::Client do
4
4
  let(:credentials) { Aws::Credentials.new('access_key_id', 'secret_access_key') }