shoryuken 7.0.0.alpha2 → 7.0.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/.github/workflows/push.yml +2 -2
- data/.github/workflows/specs.yml +38 -43
- data/.github/workflows/verify-action-pins.yml +1 -1
- data/.gitignore +3 -0
- data/.rspec +1 -0
- data/.ruby-version +1 -1
- data/.yard-lint.yml +279 -0
- data/CHANGELOG.md +69 -1
- data/Gemfile +1 -1
- data/README.md +2 -7
- data/Rakefile +4 -10
- data/bin/clean_localstack +52 -0
- data/bin/cli/base.rb +21 -0
- data/bin/cli/sqs.rb +61 -2
- data/bin/integrations +275 -0
- data/bin/scenario +154 -0
- data/bin/shoryuken +1 -1
- data/lib/{shoryuken/extensions/active_job_extensions.rb → active_job/extensions.rb} +15 -4
- data/lib/active_job/queue_adapters/shoryuken_adapter.rb +208 -0
- data/lib/active_job/queue_adapters/shoryuken_concurrent_send_adapter.rb +78 -0
- data/lib/shoryuken/active_job/current_attributes.rb +139 -0
- data/lib/shoryuken/active_job/job_wrapper.rb +28 -0
- data/lib/shoryuken/body_parser.rb +8 -0
- data/lib/shoryuken/client.rb +14 -0
- data/lib/shoryuken/default_exception_handler.rb +9 -0
- data/lib/shoryuken/default_worker_registry.rb +29 -1
- data/lib/shoryuken/environment_loader.rb +78 -8
- data/lib/shoryuken/errors.rb +33 -0
- data/lib/shoryuken/fetcher.rb +37 -1
- data/lib/shoryuken/helpers/atomic_boolean.rb +19 -5
- data/lib/shoryuken/helpers/timer_task.rb +80 -0
- data/lib/shoryuken/launcher.rb +53 -0
- data/lib/shoryuken/logging/base.rb +26 -0
- data/lib/shoryuken/logging/pretty.rb +25 -0
- data/lib/shoryuken/logging/without_timestamp.rb +25 -0
- data/lib/shoryuken/logging.rb +39 -25
- data/lib/shoryuken/manager.rb +70 -1
- data/lib/shoryuken/message.rb +114 -1
- data/lib/shoryuken/middleware/chain.rb +139 -43
- data/lib/shoryuken/middleware/entry.rb +30 -0
- data/lib/shoryuken/middleware/server/active_record.rb +8 -0
- data/lib/shoryuken/middleware/server/auto_delete.rb +10 -0
- data/lib/shoryuken/middleware/server/auto_extend_visibility.rb +27 -1
- data/lib/shoryuken/middleware/server/exponential_backoff_retry.rb +29 -0
- data/lib/shoryuken/middleware/server/timing.rb +11 -0
- data/lib/shoryuken/options.rb +129 -6
- data/lib/shoryuken/polling/base_strategy.rb +1 -0
- data/lib/shoryuken/polling/strict_priority.rb +39 -0
- data/lib/shoryuken/polling/weighted_round_robin.rb +42 -0
- data/lib/shoryuken/processor.rb +32 -1
- data/lib/shoryuken/queue.rb +93 -4
- data/lib/shoryuken/runner.rb +45 -4
- data/lib/shoryuken/util.rb +26 -1
- data/lib/shoryuken/version.rb +2 -1
- data/lib/shoryuken/worker/default_executor.rb +21 -1
- data/lib/shoryuken/worker/inline_executor.rb +24 -0
- data/lib/shoryuken/worker.rb +193 -0
- data/lib/shoryuken/worker_registry.rb +33 -0
- data/lib/shoryuken.rb +18 -6
- data/renovate.json +29 -2
- data/shoryuken.gemspec +2 -1
- data/spec/integration/.rspec +1 -0
- data/spec/integration/active_job/adapter_configuration/configuration_spec.rb +26 -0
- data/spec/integration/active_job/bulk_enqueue/bulk_enqueue_spec.rb +53 -0
- data/spec/integration/active_job/current_attributes/bulk_enqueue_spec.rb +50 -0
- data/spec/integration/active_job/current_attributes/complex_types_spec.rb +55 -0
- data/spec/integration/active_job/current_attributes/empty_context_spec.rb +41 -0
- data/spec/integration/active_job/current_attributes/full_context_spec.rb +63 -0
- data/spec/integration/active_job/current_attributes/partial_context_spec.rb +57 -0
- data/spec/integration/active_job/custom_attributes/number_attributes_spec.rb +37 -0
- data/spec/integration/active_job/custom_attributes/string_attributes_spec.rb +39 -0
- data/spec/integration/active_job/error_handling/job_wrapper_spec.rb +53 -0
- data/spec/integration/active_job/fifo_and_attributes/deduplication_spec.rb +86 -0
- data/spec/integration/active_job/retry/discard_on_spec.rb +43 -0
- data/spec/integration/active_job/retry/retry_on_spec.rb +36 -0
- data/spec/integration/active_job/roundtrip/roundtrip_spec.rb +52 -0
- data/spec/integration/active_job/scheduled/scheduled_spec.rb +76 -0
- data/spec/integration/active_record_middleware/active_record_middleware_spec.rb +84 -0
- data/spec/integration/auto_delete/auto_delete_spec.rb +53 -0
- data/spec/integration/auto_extend_visibility/auto_extend_visibility_spec.rb +57 -0
- data/spec/integration/aws_config/aws_config_spec.rb +59 -0
- data/spec/integration/batch_processing/batch_processing_spec.rb +37 -0
- data/spec/integration/body_parser/json_parser_spec.rb +45 -0
- data/spec/integration/body_parser/proc_parser_spec.rb +54 -0
- data/spec/integration/body_parser/text_parser_spec.rb +43 -0
- data/spec/integration/concurrent_processing/concurrent_processing_spec.rb +45 -0
- data/spec/integration/dead_letter_queue/dead_letter_queue_spec.rb +91 -0
- data/spec/integration/exception_handlers/exception_handlers_spec.rb +69 -0
- data/spec/integration/exponential_backoff/exponential_backoff_spec.rb +67 -0
- data/spec/integration/fifo_ordering/fifo_ordering_spec.rb +44 -0
- data/spec/integration/large_payloads/large_payloads_spec.rb +30 -0
- data/spec/integration/launcher/launcher_spec.rb +40 -0
- data/spec/integration/message_attributes/message_attributes_spec.rb +54 -0
- data/spec/integration/message_operations/message_operations_spec.rb +59 -0
- data/spec/integration/middleware_chain/empty_chain_spec.rb +11 -0
- data/spec/integration/middleware_chain/execution_order_spec.rb +33 -0
- data/spec/integration/middleware_chain/removal_spec.rb +31 -0
- data/spec/integration/middleware_chain/short_circuit_spec.rb +40 -0
- data/spec/integration/polling_strategies/polling_strategies_spec.rb +46 -0
- data/spec/integration/queue_operations/queue_operations_spec.rb +84 -0
- data/spec/integration/rails/rails_72/Gemfile +6 -0
- data/spec/integration/rails/rails_72/activejob_adapter_spec.rb +98 -0
- data/spec/integration/rails/rails_80/Gemfile +6 -0
- data/spec/integration/rails/rails_80/activejob_adapter_spec.rb +98 -0
- data/spec/integration/rails/rails_80/continuation_spec.rb +79 -0
- data/spec/integration/rails/rails_81/Gemfile +6 -0
- data/spec/integration/rails/rails_81/activejob_adapter_spec.rb +98 -0
- data/spec/integration/rails/rails_81/continuation_spec.rb +79 -0
- data/spec/integration/retry_behavior/retry_behavior_spec.rb +45 -0
- data/spec/integration/spec_helper.rb +7 -0
- data/spec/integration/strict_priority_polling/strict_priority_polling_spec.rb +58 -0
- data/spec/integration/visibility_timeout/visibility_timeout_spec.rb +37 -0
- data/spec/integration/worker_enqueueing/worker_enqueueing_spec.rb +60 -0
- data/spec/integration/worker_groups/worker_groups_spec.rb +79 -0
- data/spec/integration/worker_lifecycle/worker_lifecycle_spec.rb +33 -0
- data/spec/integrations_helper.rb +243 -0
- data/spec/lib/active_job/extensions_spec.rb +149 -0
- data/spec/lib/active_job/queue_adapters/shoryuken_adapter_spec.rb +29 -0
- data/spec/{shoryuken/extensions/active_job_concurrent_send_adapter_spec.rb → lib/active_job/queue_adapters/shoryuken_concurrent_send_adapter_spec.rb} +3 -3
- data/spec/{shoryuken/extensions/active_job_wrapper_spec.rb → lib/shoryuken/active_job/job_wrapper_spec.rb} +4 -4
- data/spec/{shoryuken → lib/shoryuken}/environment_loader_spec.rb +1 -1
- data/spec/{shoryuken → lib/shoryuken}/helpers/hash_utils_spec.rb +14 -14
- data/spec/{shoryuken → lib/shoryuken}/helpers/string_utils_spec.rb +3 -3
- data/spec/lib/shoryuken/helpers/timer_task_spec.rb +298 -0
- data/spec/{shoryuken → lib/shoryuken}/helpers_integration_spec.rb +9 -9
- data/spec/{shoryuken → lib/shoryuken}/launcher_spec.rb +22 -0
- data/spec/lib/shoryuken/logging_spec.rb +242 -0
- data/spec/lib/shoryuken/message_spec.rb +109 -0
- data/spec/lib/shoryuken/middleware/entry_spec.rb +68 -0
- data/spec/lib/shoryuken/middleware/server/active_record_spec.rb +133 -0
- data/spec/{shoryuken → lib/shoryuken}/middleware/server/auto_extend_visibility_spec.rb +50 -0
- data/spec/{shoryuken → lib/shoryuken}/options_spec.rb +2 -2
- data/spec/{shoryuken → lib/shoryuken}/util_spec.rb +1 -1
- data/spec/lib/shoryuken/version_spec.rb +17 -0
- data/spec/lib/shoryuken/worker_registry_spec.rb +63 -0
- data/spec/shared_examples_for_active_job.rb +29 -9
- data/spec/spec_helper.rb +34 -3
- metadata +230 -91
- data/.devcontainer/Dockerfile +0 -17
- data/.devcontainer/base.Dockerfile +0 -43
- data/.devcontainer/devcontainer.json +0 -35
- data/Appraisals +0 -23
- data/gemfiles/.gitignore +0 -1
- data/gemfiles/rails_7_0.gemfile +0 -19
- data/gemfiles/rails_7_1.gemfile +0 -19
- data/gemfiles/rails_7_2.gemfile +0 -19
- data/gemfiles/rails_8_0.gemfile +0 -19
- data/lib/shoryuken/extensions/active_job_adapter.rb +0 -110
- data/lib/shoryuken/extensions/active_job_concurrent_send_adapter.rb +0 -50
- data/spec/integration/launcher_spec.rb +0 -127
- data/spec/shoryuken/extensions/active_job_adapter_spec.rb +0 -8
- data/spec/shoryuken/extensions/active_job_base_spec.rb +0 -85
- /data/spec/{shoryuken → lib/shoryuken}/body_parser_spec.rb +0 -0
- /data/spec/{shoryuken → lib/shoryuken}/client_spec.rb +0 -0
- /data/spec/{shoryuken → lib/shoryuken}/default_exception_handler_spec.rb +0 -0
- /data/spec/{shoryuken → lib/shoryuken}/default_worker_registry_spec.rb +0 -0
- /data/spec/{shoryuken → lib/shoryuken}/fetcher_spec.rb +0 -0
- /data/spec/{shoryuken → lib/shoryuken}/helpers/atomic_boolean_spec.rb +0 -0
- /data/spec/{shoryuken → lib/shoryuken}/helpers/atomic_counter_spec.rb +0 -0
- /data/spec/{shoryuken → lib/shoryuken}/helpers/atomic_hash_spec.rb +0 -0
- /data/spec/{shoryuken → lib/shoryuken}/inline_message_spec.rb +0 -0
- /data/spec/{shoryuken → lib/shoryuken}/manager_spec.rb +0 -0
- /data/spec/{shoryuken → lib/shoryuken}/middleware/chain_spec.rb +0 -0
- /data/spec/{shoryuken → lib/shoryuken}/middleware/server/auto_delete_spec.rb +0 -0
- /data/spec/{shoryuken → lib/shoryuken}/middleware/server/exponential_backoff_retry_spec.rb +0 -0
- /data/spec/{shoryuken → lib/shoryuken}/middleware/server/timing_spec.rb +0 -0
- /data/spec/{shoryuken → lib/shoryuken}/polling/base_strategy_spec.rb +0 -0
- /data/spec/{shoryuken → lib/shoryuken}/polling/queue_configuration_spec.rb +0 -0
- /data/spec/{shoryuken → lib/shoryuken}/polling/strict_priority_spec.rb +0 -0
- /data/spec/{shoryuken → lib/shoryuken}/polling/weighted_round_robin_spec.rb +0 -0
- /data/spec/{shoryuken → lib/shoryuken}/processor_spec.rb +0 -0
- /data/spec/{shoryuken → lib/shoryuken}/queue_spec.rb +0 -0
- /data/spec/{shoryuken → lib/shoryuken}/runner_spec.rb +0 -0
- /data/spec/{shoryuken → lib/shoryuken}/worker/default_executor_spec.rb +0 -0
- /data/spec/{shoryuken → lib/shoryuken}/worker/inline_executor_spec.rb +0 -0
- /data/spec/{shoryuken → lib/shoryuken}/worker_spec.rb +0 -0
- /data/spec/{shoryuken_spec.rb → lib/shoryuken_spec.rb} +0 -0
data/lib/shoryuken/worker.rb
CHANGED
|
@@ -1,56 +1,244 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
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
|
|
4
44
|
module Worker
|
|
45
|
+
# Sets up the including class with Shoryuken worker functionality
|
|
46
|
+
#
|
|
47
|
+
# @param base [Class] the class including this module
|
|
48
|
+
# @return [void]
|
|
5
49
|
def self.included(base)
|
|
6
50
|
base.extend(ClassMethods)
|
|
7
51
|
base.shoryuken_class_attribute :shoryuken_options_hash
|
|
8
52
|
end
|
|
9
53
|
|
|
54
|
+
# Class methods added to classes that include Shoryuken::Worker.
|
|
55
|
+
# Provides methods for configuring the worker, enqueueing jobs, and managing middleware.
|
|
10
56
|
module ClassMethods
|
|
57
|
+
# Enqueues a job to be processed asynchronously by a Shoryuken worker.
|
|
58
|
+
#
|
|
59
|
+
# @param body [Object] The job payload that will be passed to the worker's perform method
|
|
60
|
+
# @param options [Hash] Additional options for job enqueueing
|
|
61
|
+
# @option options [String] :message_group_id FIFO queue group ID for message ordering
|
|
62
|
+
# @option options [String] :message_deduplication_id FIFO queue deduplication ID
|
|
63
|
+
# @option options [Hash] :message_attributes Custom SQS message attributes
|
|
64
|
+
# @return [String] The message ID of the enqueued job
|
|
65
|
+
#
|
|
66
|
+
# @example Basic job enqueueing
|
|
67
|
+
# MyWorker.perform_async({ user_id: 123, action: 'send_email' })
|
|
68
|
+
#
|
|
69
|
+
# @example FIFO queue with ordering
|
|
70
|
+
# MyWorker.perform_async(data, message_group_id: 'user_123')
|
|
11
71
|
def perform_async(body, options = {})
|
|
12
72
|
Shoryuken.worker_executor.perform_async(self, body, options)
|
|
13
73
|
end
|
|
14
74
|
|
|
75
|
+
# Enqueues a job to be processed after a specified time interval.
|
|
76
|
+
#
|
|
77
|
+
# @param interval [Integer, ActiveSupport::Duration] Delay in seconds, or duration object
|
|
78
|
+
# @param body [Object] The job payload that will be passed to the worker's perform method
|
|
79
|
+
# @param options [Hash] SQS message options for the delayed job
|
|
80
|
+
# @option options [String] :message_group_id FIFO queue group ID for message ordering
|
|
81
|
+
# @option options [String] :message_deduplication_id FIFO queue deduplication ID
|
|
82
|
+
# @option options [Hash] :message_attributes Custom SQS message attributes
|
|
83
|
+
# @return [String] The message ID of the enqueued job
|
|
84
|
+
#
|
|
85
|
+
# @example Delay job by 5 minutes
|
|
86
|
+
# MyWorker.perform_in(5.minutes, { user_id: 123 })
|
|
87
|
+
#
|
|
88
|
+
# @example Delay job by specific number of seconds
|
|
89
|
+
# MyWorker.perform_in(300, { user_id: 123 })
|
|
15
90
|
def perform_in(interval, body, options = {})
|
|
16
91
|
Shoryuken.worker_executor.perform_in(self, interval, body, options)
|
|
17
92
|
end
|
|
18
93
|
|
|
19
94
|
alias_method :perform_at, :perform_in
|
|
20
95
|
|
|
96
|
+
# Configures server-side middleware chain for this worker class.
|
|
97
|
+
# Middleware runs before and after job processing, similar to Rack middleware.
|
|
98
|
+
#
|
|
99
|
+
# @yield [Shoryuken::Middleware::Chain] The middleware chain for configuration
|
|
100
|
+
# @return [Shoryuken::Middleware::Chain] The configured middleware chain
|
|
101
|
+
#
|
|
102
|
+
# @example Adding custom middleware
|
|
103
|
+
# class MyWorker
|
|
104
|
+
# include Shoryuken::Worker
|
|
105
|
+
#
|
|
106
|
+
# server_middleware do |chain|
|
|
107
|
+
# chain.add MyCustomMiddleware
|
|
108
|
+
# chain.remove Shoryuken::Middleware::Server::ActiveRecord
|
|
109
|
+
# end
|
|
110
|
+
# end
|
|
21
111
|
def server_middleware
|
|
22
112
|
@_server_chain ||= Shoryuken.server_middleware.dup
|
|
23
113
|
yield @_server_chain if block_given?
|
|
24
114
|
@_server_chain
|
|
25
115
|
end
|
|
26
116
|
|
|
117
|
+
# Configures worker options including queue assignment, processing behavior,
|
|
118
|
+
# and SQS-specific settings. This is the main configuration method for workers.
|
|
119
|
+
#
|
|
120
|
+
# @param opts [Hash] Configuration options for the worker
|
|
121
|
+
# @option opts [String, Array<String>] :queue Queue name(s) this worker processes
|
|
122
|
+
# @option opts [Boolean] :batch (false) Process messages in batches of up to 10
|
|
123
|
+
# @option opts [Boolean] :auto_delete (false) Automatically delete messages after processing
|
|
124
|
+
# @option opts [Boolean] :auto_visibility_timeout (false) Automatically extend message visibility
|
|
125
|
+
# @option opts [Array<Integer>] :retry_intervals Exponential backoff retry intervals in seconds
|
|
126
|
+
# @option opts [Hash] :sqs Additional SQS client options
|
|
127
|
+
#
|
|
128
|
+
# @example Basic worker configuration
|
|
129
|
+
# class MyWorker
|
|
130
|
+
# include Shoryuken::Worker
|
|
131
|
+
# shoryuken_options queue: 'my_queue'
|
|
132
|
+
#
|
|
133
|
+
# def perform(sqs_msg, body)
|
|
134
|
+
# # Process the message
|
|
135
|
+
# end
|
|
136
|
+
# end
|
|
137
|
+
#
|
|
138
|
+
# @example Worker with auto-delete and retries
|
|
139
|
+
# class ReliableWorker
|
|
140
|
+
# include Shoryuken::Worker
|
|
141
|
+
# shoryuken_options queue: 'important_queue',
|
|
142
|
+
# auto_delete: true,
|
|
143
|
+
# retry_intervals: [1, 5, 25, 125]
|
|
144
|
+
# end
|
|
145
|
+
#
|
|
146
|
+
# @example Batch processing worker
|
|
147
|
+
# class BatchWorker
|
|
148
|
+
# include Shoryuken::Worker
|
|
149
|
+
# shoryuken_options queue: 'batch_queue', batch: true
|
|
150
|
+
#
|
|
151
|
+
# def perform(sqs_msgs, bodies)
|
|
152
|
+
# # Process array of up to 10 messages
|
|
153
|
+
# bodies.each { |body| process_item(body) }
|
|
154
|
+
# end
|
|
155
|
+
# end
|
|
156
|
+
#
|
|
157
|
+
# @example Multiple queues with priorities
|
|
158
|
+
# class MultiQueueWorker
|
|
159
|
+
# include Shoryuken::Worker
|
|
160
|
+
# shoryuken_options queue: ['high_priority', 'low_priority']
|
|
161
|
+
# end
|
|
162
|
+
#
|
|
163
|
+
# @example Auto-extending visibility timeout for long-running jobs
|
|
164
|
+
# class LongRunningWorker
|
|
165
|
+
# include Shoryuken::Worker
|
|
166
|
+
# shoryuken_options queue: 'slow_queue',
|
|
167
|
+
# auto_visibility_timeout: true
|
|
168
|
+
#
|
|
169
|
+
# def perform(sqs_msg, body)
|
|
170
|
+
# # Long processing that might exceed visibility timeout
|
|
171
|
+
# complex_processing(body)
|
|
172
|
+
# end
|
|
173
|
+
# end
|
|
27
174
|
def shoryuken_options(opts = {})
|
|
28
175
|
self.shoryuken_options_hash = get_shoryuken_options.merge(stringify_keys(opts || {}))
|
|
29
176
|
normalize_worker_queue!
|
|
30
177
|
end
|
|
31
178
|
|
|
179
|
+
# Checks if automatic visibility timeout extension is enabled for this worker.
|
|
180
|
+
# When enabled, Shoryuken automatically extends the message visibility timeout
|
|
181
|
+
# during processing to prevent the message from becoming visible to other consumers.
|
|
182
|
+
#
|
|
183
|
+
# @return [Boolean] true if auto visibility timeout is enabled
|
|
184
|
+
#
|
|
185
|
+
# @see #shoryuken_options Documentation for enabling auto_visibility_timeout
|
|
32
186
|
def auto_visibility_timeout?
|
|
33
187
|
!!get_shoryuken_options['auto_visibility_timeout']
|
|
34
188
|
end
|
|
35
189
|
|
|
190
|
+
# Checks if exponential backoff retry is configured for this worker.
|
|
191
|
+
# When retry intervals are specified, failed jobs will be retried with
|
|
192
|
+
# increasing delays between attempts.
|
|
193
|
+
#
|
|
194
|
+
# @return [Boolean] true if retry intervals are configured
|
|
195
|
+
#
|
|
196
|
+
# @example Configuring exponential backoff
|
|
197
|
+
# shoryuken_options retry_intervals: [1, 5, 25, 125, 625]
|
|
198
|
+
# # Will retry after 1s, 5s, 25s, 125s, then 625s before giving up
|
|
199
|
+
#
|
|
200
|
+
# @see #shoryuken_options Documentation for configuring retry_intervals
|
|
36
201
|
def exponential_backoff?
|
|
37
202
|
!!get_shoryuken_options['retry_intervals']
|
|
38
203
|
end
|
|
39
204
|
|
|
205
|
+
# Checks if automatic message deletion is enabled for this worker.
|
|
206
|
+
# When enabled, successfully processed messages are automatically deleted
|
|
207
|
+
# from the SQS queue. When disabled, you must manually delete messages
|
|
208
|
+
# or they will become visible again after the visibility timeout.
|
|
209
|
+
#
|
|
210
|
+
# @return [Boolean] true if auto delete is enabled
|
|
211
|
+
#
|
|
212
|
+
# @example Manual message deletion when auto_delete is false
|
|
213
|
+
# def perform(sqs_msg, body)
|
|
214
|
+
# process_message(body)
|
|
215
|
+
# # Manually delete the message after successful processing
|
|
216
|
+
# sqs_msg.delete
|
|
217
|
+
# end
|
|
218
|
+
#
|
|
219
|
+
# @see #shoryuken_options Documentation for enabling auto_delete
|
|
40
220
|
def auto_delete?
|
|
41
221
|
!!(get_shoryuken_options['delete'] || get_shoryuken_options['auto_delete'])
|
|
42
222
|
end
|
|
43
223
|
|
|
224
|
+
# Returns the shoryuken options for this worker class
|
|
225
|
+
# @return [Hash] the options hash
|
|
44
226
|
def get_shoryuken_options # :nodoc:
|
|
45
227
|
shoryuken_options_hash || Shoryuken.default_worker_options
|
|
46
228
|
end
|
|
47
229
|
|
|
230
|
+
# Converts hash keys to strings
|
|
231
|
+
# @param hash [Hash] the hash to convert
|
|
232
|
+
# @return [Hash] hash with string keys
|
|
48
233
|
def stringify_keys(hash) # :nodoc:
|
|
49
234
|
new_hash = {}
|
|
50
235
|
hash.each { |key, value| new_hash[key.to_s] = value }
|
|
51
236
|
new_hash
|
|
52
237
|
end
|
|
53
238
|
|
|
239
|
+
# Defines inheritable class attributes for workers
|
|
240
|
+
# @param attrs [Array<Symbol>] attribute names to define
|
|
241
|
+
# @return [void]
|
|
54
242
|
def shoryuken_class_attribute(*attrs) # :nodoc:
|
|
55
243
|
attrs.each do |name|
|
|
56
244
|
singleton_class.instance_eval do
|
|
@@ -108,6 +296,8 @@ module Shoryuken
|
|
|
108
296
|
|
|
109
297
|
private
|
|
110
298
|
|
|
299
|
+
# Normalizes the queue option and registers the worker
|
|
300
|
+
# @return [void]
|
|
111
301
|
def normalize_worker_queue!
|
|
112
302
|
queue = shoryuken_options_hash['queue']
|
|
113
303
|
if queue.respond_to?(:call)
|
|
@@ -125,6 +315,9 @@ module Shoryuken
|
|
|
125
315
|
[shoryuken_options_hash['queue']].flatten.compact.each(&method(:register_worker))
|
|
126
316
|
end
|
|
127
317
|
|
|
318
|
+
# Registers this worker class for a queue
|
|
319
|
+
# @param queue [String] the queue name
|
|
320
|
+
# @return [void]
|
|
128
321
|
def register_worker(queue)
|
|
129
322
|
Shoryuken.register_worker(queue, self)
|
|
130
323
|
end
|
|
@@ -1,33 +1,66 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Shoryuken
|
|
4
|
+
# Abstract base class for worker registries.
|
|
5
|
+
# Defines the interface for storing and retrieving worker classes.
|
|
6
|
+
# @abstract Subclass and implement all methods to create a custom registry
|
|
4
7
|
class WorkerRegistry
|
|
8
|
+
# Checks if the workers for a queue support batch message processing
|
|
9
|
+
#
|
|
10
|
+
# @param _queue [String] the queue name
|
|
11
|
+
# @return [Boolean] true if batch processing is supported
|
|
12
|
+
# @raise [NotImplementedError] if not implemented by subclass
|
|
5
13
|
def batch_receive_messages?(_queue)
|
|
6
14
|
# true if the workers for queue support batch processing of messages
|
|
7
15
|
fail NotImplementedError
|
|
8
16
|
end
|
|
9
17
|
|
|
18
|
+
# Removes all worker registrations
|
|
19
|
+
#
|
|
20
|
+
# @return [void]
|
|
21
|
+
# @raise [NotImplementedError] if not implemented by subclass
|
|
10
22
|
def clear
|
|
11
23
|
# must remove all worker registrations
|
|
12
24
|
fail NotImplementedError
|
|
13
25
|
end
|
|
14
26
|
|
|
27
|
+
# Fetches a worker instance for processing a message
|
|
28
|
+
#
|
|
29
|
+
# @param _queue [String] the queue name
|
|
30
|
+
# @param _message [Shoryuken::Message, Array<Shoryuken::Message>] the message or batch
|
|
31
|
+
# @return [Object] a worker instance
|
|
32
|
+
# @raise [NotImplementedError] if not implemented by subclass
|
|
15
33
|
def fetch_worker(_queue, _message)
|
|
16
34
|
# must return an instance of the worker that handles
|
|
17
35
|
# message received on queue
|
|
18
36
|
fail NotImplementedError
|
|
19
37
|
end
|
|
20
38
|
|
|
39
|
+
# Returns a list of all queues with registered workers
|
|
40
|
+
#
|
|
41
|
+
# @return [Array<String>] the queue names
|
|
42
|
+
# @raise [NotImplementedError] if not implemented by subclass
|
|
21
43
|
def queues
|
|
22
44
|
# must return a list of all queues with registered workers
|
|
23
45
|
fail NotImplementedError
|
|
24
46
|
end
|
|
25
47
|
|
|
48
|
+
# Registers a worker class for a queue
|
|
49
|
+
#
|
|
50
|
+
# @param _queue [String] the queue name
|
|
51
|
+
# @param _clazz [Class] the worker class
|
|
52
|
+
# @return [void]
|
|
53
|
+
# @raise [NotImplementedError] if not implemented by subclass
|
|
26
54
|
def register_worker(_queue, _clazz)
|
|
27
55
|
# must register the worker as a consumer of messages from queue
|
|
28
56
|
fail NotImplementedError
|
|
29
57
|
end
|
|
30
58
|
|
|
59
|
+
# Returns all worker classes registered for a queue
|
|
60
|
+
#
|
|
61
|
+
# @param _queue [String] the queue name
|
|
62
|
+
# @return [Array<Class>] the worker classes, or empty array
|
|
63
|
+
# @raise [NotImplementedError] if not implemented by subclass
|
|
31
64
|
def workers(_queue)
|
|
32
65
|
# must return the list of workers registered for queue, or []
|
|
33
66
|
fail NotImplementedError
|
data/lib/shoryuken.rb
CHANGED
|
@@ -1,25 +1,37 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'yaml'
|
|
4
|
-
require 'json'
|
|
5
3
|
require 'aws-sdk-sqs'
|
|
4
|
+
require 'json'
|
|
5
|
+
require 'logger'
|
|
6
6
|
require 'time'
|
|
7
7
|
require 'concurrent'
|
|
8
8
|
require 'forwardable'
|
|
9
9
|
require 'zeitwerk'
|
|
10
|
+
require 'yaml'
|
|
10
11
|
|
|
11
12
|
# Set up Zeitwerk loader
|
|
12
13
|
loader = Zeitwerk::Loader.for_gem
|
|
13
|
-
loader.ignore("#{__dir__}/
|
|
14
|
+
loader.ignore("#{__dir__}/active_job")
|
|
14
15
|
loader.setup
|
|
15
16
|
|
|
17
|
+
# Shoryuken is a super efficient AWS SQS thread based message processor.
|
|
18
|
+
# It provides a simple interface to process SQS messages using Ruby workers.
|
|
16
19
|
module Shoryuken
|
|
17
20
|
extend SingleForwardable
|
|
18
21
|
|
|
22
|
+
# Returns the global Shoryuken configuration options instance.
|
|
23
|
+
# This is used internally for storing and accessing configuration settings.
|
|
24
|
+
#
|
|
25
|
+
# @return [Shoryuken::Options] The global options instance
|
|
19
26
|
def self.shoryuken_options
|
|
20
27
|
@_shoryuken_options ||= Shoryuken::Options.new
|
|
21
28
|
end
|
|
22
29
|
|
|
30
|
+
# Checks if the Shoryuken server is running and healthy.
|
|
31
|
+
# A server is considered healthy when all configured processing groups
|
|
32
|
+
# are running and able to process messages.
|
|
33
|
+
#
|
|
34
|
+
# @return [Boolean] true if the server is healthy
|
|
23
35
|
def self.healthy?
|
|
24
36
|
Shoryuken::Runner.instance.healthy?
|
|
25
37
|
end
|
|
@@ -77,7 +89,7 @@ module Shoryuken
|
|
|
77
89
|
end
|
|
78
90
|
|
|
79
91
|
if Shoryuken.active_job?
|
|
80
|
-
require '
|
|
81
|
-
require '
|
|
82
|
-
require '
|
|
92
|
+
require 'active_job/extensions'
|
|
93
|
+
require 'active_job/queue_adapters/shoryuken_adapter'
|
|
94
|
+
require 'active_job/queue_adapters/shoryuken_concurrent_send_adapter'
|
|
83
95
|
end
|
data/renovate.json
CHANGED
|
@@ -3,14 +3,41 @@
|
|
|
3
3
|
"extends": [
|
|
4
4
|
"config:recommended"
|
|
5
5
|
],
|
|
6
|
+
"minimumReleaseAge": "7 days",
|
|
6
7
|
"github-actions": {
|
|
7
8
|
"enabled": true,
|
|
8
9
|
"pinDigests": true
|
|
9
10
|
},
|
|
11
|
+
"bundler": {
|
|
12
|
+
"enabled": true,
|
|
13
|
+
"managerFilePatterns": [
|
|
14
|
+
"/(^|/)Gemfile$/",
|
|
15
|
+
"/\\.gemfile$/",
|
|
16
|
+
"/(^|/)gems\\.rb$/",
|
|
17
|
+
"/spec/gemfiles/.+\\.gemfile$/",
|
|
18
|
+
"/spec/integration/.*/Gemfile$/"
|
|
19
|
+
]
|
|
20
|
+
},
|
|
10
21
|
"packageRules": [
|
|
11
22
|
{
|
|
12
|
-
"matchManagers": [
|
|
13
|
-
|
|
23
|
+
"matchManagers": [
|
|
24
|
+
"bundler"
|
|
25
|
+
],
|
|
26
|
+
"matchFileNames": [
|
|
27
|
+
"spec/gemfiles/**"
|
|
28
|
+
],
|
|
29
|
+
"groupName": "Rails test dependencies",
|
|
30
|
+
"description": "Group Rails version-specific test Gemfiles together"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"matchManagers": [
|
|
34
|
+
"bundler"
|
|
35
|
+
],
|
|
36
|
+
"matchFileNames": [
|
|
37
|
+
"spec/integration/**/Gemfile"
|
|
38
|
+
],
|
|
39
|
+
"groupName": "Integration test dependencies",
|
|
40
|
+
"description": "Group integration test Gemfiles together"
|
|
14
41
|
}
|
|
15
42
|
]
|
|
16
43
|
}
|
data/shoryuken.gemspec
CHANGED
|
@@ -25,6 +25,7 @@ Gem::Specification.new do |spec|
|
|
|
25
25
|
spec.add_development_dependency 'ostruct'
|
|
26
26
|
spec.add_development_dependency 'rake'
|
|
27
27
|
spec.add_development_dependency 'rspec'
|
|
28
|
+
spec.add_development_dependency 'warning'
|
|
28
29
|
|
|
29
|
-
spec.required_ruby_version = '>= 3.
|
|
30
|
+
spec.required_ruby_version = '>= 3.2.0'
|
|
30
31
|
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
--require spec_helper
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This spec tests ActiveJob adapter configuration including adapter type,
|
|
4
|
+
# Rails 7.2+ transaction commit hook, and singleton pattern.
|
|
5
|
+
|
|
6
|
+
setup_active_job
|
|
7
|
+
|
|
8
|
+
class ConfigTestJob < ActiveJob::Base
|
|
9
|
+
queue_as :config_test
|
|
10
|
+
|
|
11
|
+
def perform(data)
|
|
12
|
+
"Processed: #{data}"
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
adapter = ActiveJob::Base.queue_adapter
|
|
17
|
+
assert_equal("ActiveJob::QueueAdapters::ShoryukenAdapter", adapter.class.name)
|
|
18
|
+
|
|
19
|
+
adapter_instance = ActiveJob::QueueAdapters::ShoryukenAdapter.new
|
|
20
|
+
assert(adapter_instance.respond_to?(:enqueue_after_transaction_commit?))
|
|
21
|
+
assert_equal(true, adapter_instance.enqueue_after_transaction_commit?)
|
|
22
|
+
|
|
23
|
+
instance1 = ActiveJob::QueueAdapters::ShoryukenAdapter.instance
|
|
24
|
+
instance2 = ActiveJob::QueueAdapters::ShoryukenAdapter.instance
|
|
25
|
+
assert_equal(instance1.object_id, instance2.object_id)
|
|
26
|
+
assert(instance1.is_a?(ActiveJob::QueueAdapters::ShoryukenAdapter))
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Bulk enqueue integration test
|
|
4
|
+
# Tests perform_all_later with the new enqueue_all method using SQS batch API
|
|
5
|
+
|
|
6
|
+
setup_localstack
|
|
7
|
+
setup_active_job
|
|
8
|
+
|
|
9
|
+
queue_name = DT.queue
|
|
10
|
+
create_test_queue(queue_name)
|
|
11
|
+
|
|
12
|
+
class BulkTestJob < ActiveJob::Base
|
|
13
|
+
def perform(index, data)
|
|
14
|
+
DT[:executions] << {
|
|
15
|
+
index: index,
|
|
16
|
+
data: data,
|
|
17
|
+
job_id: job_id,
|
|
18
|
+
executed_at: Time.now
|
|
19
|
+
}
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
BulkTestJob.queue_as(queue_name)
|
|
24
|
+
|
|
25
|
+
Shoryuken.add_group('default', 1)
|
|
26
|
+
Shoryuken.add_queue(queue_name, 1, 'default')
|
|
27
|
+
Shoryuken.register_worker(queue_name, Shoryuken::ActiveJob::JobWrapper)
|
|
28
|
+
|
|
29
|
+
jobs = (1..15).map { |i| BulkTestJob.new(i, "payload_#{i}") }
|
|
30
|
+
|
|
31
|
+
# Use perform_all_later which should call enqueue_all
|
|
32
|
+
ActiveJob.perform_all_later(jobs)
|
|
33
|
+
|
|
34
|
+
successfully_enqueued_count = jobs.count(&:successfully_enqueued?)
|
|
35
|
+
assert_equal(15, successfully_enqueued_count, "Expected all 15 jobs to be marked as successfully enqueued")
|
|
36
|
+
|
|
37
|
+
poll_queues_until(timeout: 45) do
|
|
38
|
+
DT[:executions].size >= 15
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
assert_equal(15, DT[:executions].size, "Expected 15 job executions, got #{DT[:executions].size}")
|
|
42
|
+
|
|
43
|
+
executed_indices = DT[:executions].map { |e| e[:index] }.sort
|
|
44
|
+
expected_indices = (1..15).to_a
|
|
45
|
+
assert_equal(expected_indices, executed_indices, "All job indices should be present")
|
|
46
|
+
|
|
47
|
+
DT[:executions].each do |execution|
|
|
48
|
+
expected_data = "payload_#{execution[:index]}"
|
|
49
|
+
assert_equal(expected_data, execution[:data], "Job #{execution[:index]} should have correct data")
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
job_ids = DT[:executions].map { |e| e[:job_id] }
|
|
53
|
+
assert_equal(15, job_ids.uniq.size, "All job IDs should be unique")
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# CurrentAttributes are persisted correctly when using bulk enqueue (perform_all_later)
|
|
4
|
+
|
|
5
|
+
setup_localstack
|
|
6
|
+
setup_active_job
|
|
7
|
+
|
|
8
|
+
require 'active_support/current_attributes'
|
|
9
|
+
require 'shoryuken/active_job/current_attributes'
|
|
10
|
+
|
|
11
|
+
queue_name = DT.queue
|
|
12
|
+
create_test_queue(queue_name)
|
|
13
|
+
|
|
14
|
+
class TestCurrent < ActiveSupport::CurrentAttributes
|
|
15
|
+
attribute :user_id, :tenant_id
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
Shoryuken::ActiveJob::CurrentAttributes.persist(TestCurrent)
|
|
19
|
+
|
|
20
|
+
class BulkCurrentAttributesTestJob < ActiveJob::Base
|
|
21
|
+
def perform(index)
|
|
22
|
+
DT[:executions] << {
|
|
23
|
+
index: index,
|
|
24
|
+
user_id: TestCurrent.user_id,
|
|
25
|
+
tenant_id: TestCurrent.tenant_id
|
|
26
|
+
}
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
BulkCurrentAttributesTestJob.queue_as(queue_name)
|
|
31
|
+
|
|
32
|
+
Shoryuken.add_group('default', 1)
|
|
33
|
+
Shoryuken.add_queue(queue_name, 1, 'default')
|
|
34
|
+
Shoryuken.register_worker(queue_name, Shoryuken::ActiveJob::JobWrapper)
|
|
35
|
+
|
|
36
|
+
TestCurrent.user_id = 'bulk-user-123'
|
|
37
|
+
TestCurrent.tenant_id = 'bulk-tenant'
|
|
38
|
+
|
|
39
|
+
jobs = (1..3).map { |i| BulkCurrentAttributesTestJob.new(i) }
|
|
40
|
+
ActiveJob.perform_all_later(jobs)
|
|
41
|
+
|
|
42
|
+
TestCurrent.reset
|
|
43
|
+
|
|
44
|
+
poll_queues_until(timeout: 30) { DT[:executions].size >= 3 }
|
|
45
|
+
|
|
46
|
+
assert_equal(3, DT[:executions].size)
|
|
47
|
+
DT[:executions].each do |job|
|
|
48
|
+
assert_equal('bulk-user-123', job[:user_id])
|
|
49
|
+
assert_equal('bulk-tenant', job[:tenant_id])
|
|
50
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# CurrentAttributes with complex data types (hashes, arrays, symbols) are serialized and restored
|
|
4
|
+
|
|
5
|
+
setup_localstack
|
|
6
|
+
setup_active_job
|
|
7
|
+
|
|
8
|
+
require 'active_support/current_attributes'
|
|
9
|
+
require 'shoryuken/active_job/current_attributes'
|
|
10
|
+
|
|
11
|
+
queue_name = DT.queue
|
|
12
|
+
create_test_queue(queue_name)
|
|
13
|
+
|
|
14
|
+
class TestCurrent < ActiveSupport::CurrentAttributes
|
|
15
|
+
attribute :user_id, :tenant_id
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
Shoryuken::ActiveJob::CurrentAttributes.persist(TestCurrent)
|
|
19
|
+
|
|
20
|
+
class ComplexTypesTestJob < ActiveJob::Base
|
|
21
|
+
def perform
|
|
22
|
+
DT[:executions] << {
|
|
23
|
+
user_id: TestCurrent.user_id,
|
|
24
|
+
tenant_id: TestCurrent.tenant_id
|
|
25
|
+
}
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
ComplexTypesTestJob.queue_as(queue_name)
|
|
30
|
+
|
|
31
|
+
Shoryuken.add_group('default', 1)
|
|
32
|
+
Shoryuken.add_queue(queue_name, 1, 'default')
|
|
33
|
+
Shoryuken.register_worker(queue_name, Shoryuken::ActiveJob::JobWrapper)
|
|
34
|
+
|
|
35
|
+
TestCurrent.user_id = { role: :admin, permissions: [:read, :write, :delete] }
|
|
36
|
+
TestCurrent.tenant_id = [:tenant_a, :tenant_b]
|
|
37
|
+
|
|
38
|
+
ComplexTypesTestJob.perform_later
|
|
39
|
+
|
|
40
|
+
TestCurrent.reset
|
|
41
|
+
|
|
42
|
+
poll_queues_until(timeout: 30) { DT[:executions].size >= 1 }
|
|
43
|
+
|
|
44
|
+
result = DT[:executions].first
|
|
45
|
+
|
|
46
|
+
user_data = result[:user_id]
|
|
47
|
+
assert(user_data.is_a?(Hash))
|
|
48
|
+
role = user_data['role'] || user_data[:role]
|
|
49
|
+
assert_equal('admin', role.to_s)
|
|
50
|
+
permissions = user_data['permissions'] || user_data[:permissions]
|
|
51
|
+
assert_equal(3, permissions.size)
|
|
52
|
+
|
|
53
|
+
tenant_data = result[:tenant_id]
|
|
54
|
+
assert(tenant_data.is_a?(Array))
|
|
55
|
+
assert_equal(2, tenant_data.size)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# CurrentAttributes without any values set result in nil attributes during job execution
|
|
4
|
+
|
|
5
|
+
setup_localstack
|
|
6
|
+
setup_active_job
|
|
7
|
+
|
|
8
|
+
require 'active_support/current_attributes'
|
|
9
|
+
require 'shoryuken/active_job/current_attributes'
|
|
10
|
+
|
|
11
|
+
queue_name = DT.queue
|
|
12
|
+
create_test_queue(queue_name)
|
|
13
|
+
|
|
14
|
+
class TestCurrent < ActiveSupport::CurrentAttributes
|
|
15
|
+
attribute :user_id, :tenant_id
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
Shoryuken::ActiveJob::CurrentAttributes.persist(TestCurrent)
|
|
19
|
+
|
|
20
|
+
class EmptyContextTestJob < ActiveJob::Base
|
|
21
|
+
def perform
|
|
22
|
+
DT[:executions] << {
|
|
23
|
+
user_id: TestCurrent.user_id,
|
|
24
|
+
tenant_id: TestCurrent.tenant_id
|
|
25
|
+
}
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
EmptyContextTestJob.queue_as(queue_name)
|
|
30
|
+
|
|
31
|
+
Shoryuken.add_group('default', 1)
|
|
32
|
+
Shoryuken.add_queue(queue_name, 1, 'default')
|
|
33
|
+
Shoryuken.register_worker(queue_name, Shoryuken::ActiveJob::JobWrapper)
|
|
34
|
+
|
|
35
|
+
EmptyContextTestJob.perform_later
|
|
36
|
+
|
|
37
|
+
poll_queues_until(timeout: 30) { DT[:executions].size >= 1 }
|
|
38
|
+
|
|
39
|
+
result = DT[:executions].first
|
|
40
|
+
assert(result[:user_id].nil?)
|
|
41
|
+
assert(result[:tenant_id].nil?)
|