shoryuken 7.0.0.alpha1 → 7.0.0.rc1

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 (113) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/push.yml +3 -3
  3. data/.github/workflows/specs.yml +27 -17
  4. data/.github/workflows/verify-action-pins.yml +1 -1
  5. data/.rspec +2 -1
  6. data/.ruby-version +1 -1
  7. data/Appraisals +6 -18
  8. data/CHANGELOG.md +200 -142
  9. data/Gemfile +1 -0
  10. data/README.md +12 -13
  11. data/bin/cli/base.rb +1 -2
  12. data/bin/cli/sqs.rb +6 -5
  13. data/bin/shoryuken +3 -2
  14. data/gemfiles/rails_7_2.gemfile +1 -0
  15. data/gemfiles/rails_8_0.gemfile +1 -0
  16. data/gemfiles/{rails_7_1.gemfile → rails_8_1.gemfile} +2 -1
  17. data/lib/shoryuken/body_parser.rb +3 -1
  18. data/lib/shoryuken/client.rb +2 -0
  19. data/lib/shoryuken/default_exception_handler.rb +2 -0
  20. data/lib/shoryuken/default_worker_registry.rb +11 -11
  21. data/lib/shoryuken/environment_loader.rb +6 -6
  22. data/lib/shoryuken/extensions/active_job_adapter.rb +21 -6
  23. data/lib/shoryuken/extensions/active_job_concurrent_send_adapter.rb +5 -5
  24. data/lib/shoryuken/extensions/active_job_extensions.rb +2 -0
  25. data/lib/shoryuken/fetcher.rb +4 -2
  26. data/lib/shoryuken/helpers/atomic_boolean.rb +44 -0
  27. data/lib/shoryuken/helpers/atomic_counter.rb +104 -0
  28. data/lib/shoryuken/helpers/atomic_hash.rb +182 -0
  29. data/lib/shoryuken/helpers/hash_utils.rb +56 -0
  30. data/lib/shoryuken/helpers/string_utils.rb +65 -0
  31. data/lib/shoryuken/helpers/timer_task.rb +66 -0
  32. data/lib/shoryuken/inline_message.rb +22 -0
  33. data/lib/shoryuken/launcher.rb +16 -0
  34. data/lib/shoryuken/logging/base.rb +26 -0
  35. data/lib/shoryuken/logging/pretty.rb +25 -0
  36. data/lib/shoryuken/logging/without_timestamp.rb +25 -0
  37. data/lib/shoryuken/logging.rb +6 -12
  38. data/lib/shoryuken/manager.rb +6 -4
  39. data/lib/shoryuken/message.rb +116 -1
  40. data/lib/shoryuken/middleware/chain.rb +140 -43
  41. data/lib/shoryuken/middleware/entry.rb +30 -0
  42. data/lib/shoryuken/middleware/server/active_record.rb +2 -0
  43. data/lib/shoryuken/middleware/server/auto_delete.rb +2 -0
  44. data/lib/shoryuken/middleware/server/auto_extend_visibility.rb +11 -11
  45. data/lib/shoryuken/middleware/server/exponential_backoff_retry.rb +5 -3
  46. data/lib/shoryuken/middleware/server/timing.rb +2 -0
  47. data/lib/shoryuken/options.rb +9 -5
  48. data/lib/shoryuken/polling/base_strategy.rb +126 -0
  49. data/lib/shoryuken/polling/queue_configuration.rb +103 -0
  50. data/lib/shoryuken/polling/strict_priority.rb +2 -0
  51. data/lib/shoryuken/polling/weighted_round_robin.rb +2 -0
  52. data/lib/shoryuken/processor.rb +5 -2
  53. data/lib/shoryuken/queue.rb +6 -4
  54. data/lib/shoryuken/runner.rb +12 -12
  55. data/lib/shoryuken/util.rb +6 -6
  56. data/lib/shoryuken/version.rb +3 -1
  57. data/lib/shoryuken/worker/default_executor.rb +2 -0
  58. data/lib/shoryuken/worker/inline_executor.rb +3 -1
  59. data/lib/shoryuken/worker.rb +173 -0
  60. data/lib/shoryuken/worker_registry.rb +2 -0
  61. data/lib/shoryuken.rb +8 -28
  62. data/shoryuken.gemspec +6 -6
  63. data/spec/integration/active_job_continuation_spec.rb +145 -0
  64. data/spec/integration/launcher_spec.rb +2 -3
  65. data/spec/shared_examples_for_active_job.rb +13 -8
  66. data/spec/shoryuken/body_parser_spec.rb +1 -2
  67. data/spec/shoryuken/client_spec.rb +1 -1
  68. data/spec/shoryuken/default_exception_handler_spec.rb +9 -10
  69. data/spec/shoryuken/default_worker_registry_spec.rb +1 -2
  70. data/spec/shoryuken/environment_loader_spec.rb +9 -8
  71. data/spec/shoryuken/extensions/active_job_adapter_spec.rb +2 -1
  72. data/spec/shoryuken/extensions/active_job_base_spec.rb +2 -1
  73. data/spec/shoryuken/extensions/active_job_concurrent_send_adapter_spec.rb +2 -1
  74. data/spec/shoryuken/extensions/active_job_continuation_spec.rb +110 -0
  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/timer_task_spec.rb +298 -0
  83. data/spec/shoryuken/helpers_integration_spec.rb +96 -0
  84. data/spec/shoryuken/inline_message_spec.rb +196 -0
  85. data/spec/shoryuken/launcher_spec.rb +23 -2
  86. data/spec/shoryuken/manager_spec.rb +1 -2
  87. data/spec/shoryuken/middleware/chain_spec.rb +1 -1
  88. data/spec/shoryuken/middleware/server/auto_delete_spec.rb +1 -1
  89. data/spec/shoryuken/middleware/server/auto_extend_visibility_spec.rb +1 -1
  90. data/spec/shoryuken/middleware/server/exponential_backoff_retry_spec.rb +1 -1
  91. data/spec/shoryuken/middleware/server/timing_spec.rb +1 -1
  92. data/spec/shoryuken/options_spec.rb +4 -4
  93. data/spec/shoryuken/polling/base_strategy_spec.rb +280 -0
  94. data/spec/shoryuken/polling/queue_configuration_spec.rb +195 -0
  95. data/spec/shoryuken/polling/strict_priority_spec.rb +1 -1
  96. data/spec/shoryuken/polling/weighted_round_robin_spec.rb +1 -1
  97. data/spec/shoryuken/processor_spec.rb +1 -1
  98. data/spec/shoryuken/queue_spec.rb +2 -3
  99. data/spec/shoryuken/runner_spec.rb +1 -3
  100. data/spec/shoryuken/util_spec.rb +1 -1
  101. data/spec/shoryuken/worker/default_executor_spec.rb +1 -1
  102. data/spec/shoryuken/worker/inline_executor_spec.rb +1 -1
  103. data/spec/shoryuken/worker_spec.rb +15 -11
  104. data/spec/shoryuken_spec.rb +1 -1
  105. data/spec/spec_helper.rb +16 -0
  106. metadata +72 -29
  107. data/.github/FUNDING.yml +0 -12
  108. data/gemfiles/rails_6_1.gemfile +0 -18
  109. data/gemfiles/rails_7_0.gemfile +0 -19
  110. data/lib/shoryuken/core_ext.rb +0 -69
  111. data/lib/shoryuken/polling/base.rb +0 -67
  112. data/shoryuken.jpg +0 -0
  113. data/spec/shoryuken/core_ext_spec.rb +0 -40
@@ -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
 
@@ -15,17 +16,18 @@ module Shoryuken
15
16
  include Util
16
17
  include Singleton
17
18
 
19
+ # @return [Shoryuken::Launcher, nil] the launcher instance, or nil if not yet initialized
20
+ attr_reader :launcher
21
+
18
22
  def run(options)
19
23
  self_read, self_write = IO.pipe
20
24
 
21
25
  %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"
26
+ trap sig do
27
+ self_write.puts(sig)
28
28
  end
29
+ rescue ArgumentError
30
+ puts "Signal #{sig} not supported"
29
31
  end
30
32
 
31
33
  loader = EnvironmentLoader.setup_options(options)
@@ -77,11 +79,9 @@ module Shoryuken
77
79
  Process.daemon(true, true)
78
80
 
79
81
  files_to_reopen.each do |file|
80
- begin
81
- file.reopen file.path, 'a+'
82
- file.sync = true
83
- rescue ::Exception
84
- end
82
+ file.reopen file.path, 'a+'
83
+ file.sync = true
84
+ rescue ::Exception
85
85
  end
86
86
 
87
87
  [$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 = '7.0.0.alpha1'.freeze
4
+ VERSION = '7.0.0.rc1'
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
@@ -11,7 +13,7 @@ module Shoryuken
11
13
  data_type: 'String'
12
14
  }
13
15
 
14
- sqs_msg = OpenStruct.new(
16
+ sqs_msg = InlineMessage.new(
15
17
  body: body,
16
18
  attributes: nil,
17
19
  md5_of_body: nil,
@@ -1,4 +1,46 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Shoryuken
4
+ # Worker module provides the core functionality for creating Shoryuken workers
5
+ # that process messages from Amazon SQS queues.
6
+ #
7
+ # Including this module in a class provides methods for configuring queue processing,
8
+ # enqueueing jobs, and setting up middleware. Workers can be configured for different
9
+ # processing patterns including single message processing, batch processing, and
10
+ # various retry and visibility timeout strategies.
11
+ #
12
+ # @example Basic worker implementation
13
+ # class EmailWorker
14
+ # include Shoryuken::Worker
15
+ # shoryuken_options queue: 'emails'
16
+ #
17
+ # def perform(sqs_msg, body)
18
+ # send_email(body['recipient'], body['subject'], body['content'])
19
+ # end
20
+ # end
21
+ #
22
+ # @example Advanced worker with all options
23
+ # class AdvancedWorker
24
+ # include Shoryuken::Worker
25
+ #
26
+ # shoryuken_options queue: 'advanced_queue',
27
+ # batch: false,
28
+ # auto_delete: true,
29
+ # auto_visibility_timeout: true,
30
+ # retry_intervals: [1, 5, 25, 125, 625]
31
+ #
32
+ # server_middleware do |chain|
33
+ # chain.add MyCustomMiddleware
34
+ # end
35
+ #
36
+ # def perform(sqs_msg, body)
37
+ # # Worker implementation
38
+ # end
39
+ # end
40
+ #
41
+ # @see ClassMethods#shoryuken_options Primary configuration method
42
+ # @see ClassMethods#perform_async For enqueueing jobs
43
+ # @see https://github.com/ruby-shoryuken/shoryuken/wiki/Workers Comprehensive worker documentation
2
44
  module Worker
3
45
  def self.included(base)
4
46
  base.extend(ClassMethods)
@@ -6,35 +48,166 @@ module Shoryuken
6
48
  end
7
49
 
8
50
  module ClassMethods
51
+ # Enqueues a job to be processed asynchronously by a Shoryuken worker.
52
+ #
53
+ # @param body [Object] The job payload that will be passed to the worker's perform method
54
+ # @param options [Hash] Additional options for job enqueueing
55
+ # @option options [String] :message_group_id FIFO queue group ID for message ordering
56
+ # @option options [String] :message_deduplication_id FIFO queue deduplication ID
57
+ # @option options [Hash] :message_attributes Custom SQS message attributes
58
+ # @return [String] The message ID of the enqueued job
59
+ #
60
+ # @example Basic job enqueueing
61
+ # MyWorker.perform_async({ user_id: 123, action: 'send_email' })
62
+ #
63
+ # @example FIFO queue with ordering
64
+ # MyWorker.perform_async(data, message_group_id: 'user_123')
9
65
  def perform_async(body, options = {})
10
66
  Shoryuken.worker_executor.perform_async(self, body, options)
11
67
  end
12
68
 
69
+ # Enqueues a job to be processed after a specified time interval.
70
+ #
71
+ # @param interval [Integer, ActiveSupport::Duration] Delay in seconds, or duration object
72
+ # @param body [Object] The job payload that will be passed to the worker's perform method
73
+ # @param options [Hash] Additional options for job enqueueing (see {#perform_async})
74
+ # @return [String] The message ID of the enqueued job
75
+ #
76
+ # @example Delay job by 5 minutes
77
+ # MyWorker.perform_in(5.minutes, { user_id: 123 })
78
+ #
79
+ # @example Delay job by specific number of seconds
80
+ # MyWorker.perform_in(300, { user_id: 123 })
13
81
  def perform_in(interval, body, options = {})
14
82
  Shoryuken.worker_executor.perform_in(self, interval, body, options)
15
83
  end
16
84
 
17
85
  alias_method :perform_at, :perform_in
18
86
 
87
+ # Configures server-side middleware chain for this worker class.
88
+ # Middleware runs before and after job processing, similar to Rack middleware.
89
+ #
90
+ # @yield [Shoryuken::Middleware::Chain] The middleware chain for configuration
91
+ # @return [Shoryuken::Middleware::Chain] The configured middleware chain
92
+ #
93
+ # @example Adding custom middleware
94
+ # class MyWorker
95
+ # include Shoryuken::Worker
96
+ #
97
+ # server_middleware do |chain|
98
+ # chain.add MyCustomMiddleware
99
+ # chain.remove Shoryuken::Middleware::Server::ActiveRecord
100
+ # end
101
+ # end
19
102
  def server_middleware
20
103
  @_server_chain ||= Shoryuken.server_middleware.dup
21
104
  yield @_server_chain if block_given?
22
105
  @_server_chain
23
106
  end
24
107
 
108
+ # Configures worker options including queue assignment, processing behavior,
109
+ # and SQS-specific settings. This is the main configuration method for workers.
110
+ #
111
+ # @param opts [Hash] Configuration options for the worker
112
+ # @option opts [String, Array<String>] :queue Queue name(s) this worker processes
113
+ # @option opts [Boolean] :batch (false) Process messages in batches of up to 10
114
+ # @option opts [Boolean] :auto_delete (false) Automatically delete messages after processing
115
+ # @option opts [Boolean] :auto_visibility_timeout (false) Automatically extend message visibility
116
+ # @option opts [Array<Integer>] :retry_intervals Exponential backoff retry intervals in seconds
117
+ # @option opts [Hash] :sqs Additional SQS client options
118
+ #
119
+ # @example Basic worker configuration
120
+ # class MyWorker
121
+ # include Shoryuken::Worker
122
+ # shoryuken_options queue: 'my_queue'
123
+ #
124
+ # def perform(sqs_msg, body)
125
+ # # Process the message
126
+ # end
127
+ # end
128
+ #
129
+ # @example Worker with auto-delete and retries
130
+ # class ReliableWorker
131
+ # include Shoryuken::Worker
132
+ # shoryuken_options queue: 'important_queue',
133
+ # auto_delete: true,
134
+ # retry_intervals: [1, 5, 25, 125]
135
+ # end
136
+ #
137
+ # @example Batch processing worker
138
+ # class BatchWorker
139
+ # include Shoryuken::Worker
140
+ # shoryuken_options queue: 'batch_queue', batch: true
141
+ #
142
+ # def perform(sqs_msgs, bodies)
143
+ # # Process array of up to 10 messages
144
+ # bodies.each { |body| process_item(body) }
145
+ # end
146
+ # end
147
+ #
148
+ # @example Multiple queues with priorities
149
+ # class MultiQueueWorker
150
+ # include Shoryuken::Worker
151
+ # shoryuken_options queue: ['high_priority', 'low_priority']
152
+ # end
153
+ #
154
+ # @example Auto-extending visibility timeout for long-running jobs
155
+ # class LongRunningWorker
156
+ # include Shoryuken::Worker
157
+ # shoryuken_options queue: 'slow_queue',
158
+ # auto_visibility_timeout: true
159
+ #
160
+ # def perform(sqs_msg, body)
161
+ # # Long processing that might exceed visibility timeout
162
+ # complex_processing(body)
163
+ # end
164
+ # end
25
165
  def shoryuken_options(opts = {})
26
166
  self.shoryuken_options_hash = get_shoryuken_options.merge(stringify_keys(opts || {}))
27
167
  normalize_worker_queue!
28
168
  end
29
169
 
170
+ # Checks if automatic visibility timeout extension is enabled for this worker.
171
+ # When enabled, Shoryuken automatically extends the message visibility timeout
172
+ # during processing to prevent the message from becoming visible to other consumers.
173
+ #
174
+ # @return [Boolean] true if auto visibility timeout is enabled
175
+ #
176
+ # @see #shoryuken_options Documentation for enabling auto_visibility_timeout
30
177
  def auto_visibility_timeout?
31
178
  !!get_shoryuken_options['auto_visibility_timeout']
32
179
  end
33
180
 
181
+ # Checks if exponential backoff retry is configured for this worker.
182
+ # When retry intervals are specified, failed jobs will be retried with
183
+ # increasing delays between attempts.
184
+ #
185
+ # @return [Boolean] true if retry intervals are configured
186
+ #
187
+ # @example Configuring exponential backoff
188
+ # shoryuken_options retry_intervals: [1, 5, 25, 125, 625]
189
+ # # Will retry after 1s, 5s, 25s, 125s, then 625s before giving up
190
+ #
191
+ # @see #shoryuken_options Documentation for configuring retry_intervals
34
192
  def exponential_backoff?
35
193
  !!get_shoryuken_options['retry_intervals']
36
194
  end
37
195
 
196
+ # Checks if automatic message deletion is enabled for this worker.
197
+ # When enabled, successfully processed messages are automatically deleted
198
+ # from the SQS queue. When disabled, you must manually delete messages
199
+ # or they will become visible again after the visibility timeout.
200
+ #
201
+ # @return [Boolean] true if auto delete is enabled
202
+ #
203
+ # @example Manual message deletion when auto_delete is false
204
+ # def perform(sqs_msg, body)
205
+ # process_message(body)
206
+ # # Manually delete the message after successful processing
207
+ # sqs_msg.delete
208
+ # end
209
+ #
210
+ # @see #shoryuken_options Documentation for enabling auto_delete
38
211
  def auto_delete?
39
212
  !!(get_shoryuken_options['delete'] || get_shoryuken_options['auto_delete'])
40
213
  end
@@ -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,38 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'yaml'
2
4
  require 'json'
3
5
  require 'aws-sdk-sqs'
4
6
  require 'time'
5
7
  require 'concurrent'
6
8
  require 'forwardable'
9
+ require 'zeitwerk'
7
10
 
8
- require 'shoryuken/version'
9
- require 'shoryuken/core_ext'
10
- require 'shoryuken/util'
11
- require 'shoryuken/logging'
12
- require 'shoryuken/environment_loader'
13
- require 'shoryuken/queue'
14
- require 'shoryuken/message'
15
- require 'shoryuken/client'
16
- require 'shoryuken/worker'
17
- require 'shoryuken/worker/default_executor'
18
- require 'shoryuken/worker/inline_executor'
19
- require 'shoryuken/worker_registry'
20
- require 'shoryuken/default_worker_registry'
21
- require 'shoryuken/default_exception_handler'
22
- require 'shoryuken/middleware/chain'
23
- require 'shoryuken/middleware/server/auto_delete'
24
- Shoryuken::Middleware::Server.autoload :AutoExtendVisibility, 'shoryuken/middleware/server/auto_extend_visibility'
25
- require 'shoryuken/middleware/server/exponential_backoff_retry'
26
- require 'shoryuken/middleware/server/timing'
27
- require 'shoryuken/polling/base'
28
- require 'shoryuken/polling/weighted_round_robin'
29
- require 'shoryuken/polling/strict_priority'
30
- require 'shoryuken/manager'
31
- require 'shoryuken/launcher'
32
- require 'shoryuken/processor'
33
- require 'shoryuken/body_parser'
34
- require 'shoryuken/fetcher'
35
- require 'shoryuken/options'
11
+ # Set up Zeitwerk loader
12
+ loader = Zeitwerk::Loader.for_gem
13
+ loader.ignore("#{__dir__}/shoryuken/extensions")
14
+ loader.setup
36
15
 
37
16
  module Shoryuken
38
17
  extend SingleForwardable
@@ -75,6 +54,7 @@ module Shoryuken
75
54
  :exception_handlers=,
76
55
  :options,
77
56
  :logger,
57
+ :logger=,
78
58
  :register_worker,
79
59
  :configure_server,
80
60
  :server?,
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,14 +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'
21
25
  spec.add_development_dependency 'ostruct'
22
26
  spec.add_development_dependency 'rake'
23
27
  spec.add_development_dependency 'rspec'
24
28
 
25
- spec.add_dependency 'aws-sdk-sqs', '>= 1.66.0'
26
- spec.add_dependency 'concurrent-ruby'
27
- spec.add_dependency 'thor'
28
-
29
- spec.required_ruby_version = '>= 3.0.0'
29
+ spec.required_ruby_version = '>= 3.1.0'
30
30
  end