shoryuken 6.2.1 → 7.0.2
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 +36 -0
- data/.github/workflows/specs.yml +49 -44
- data/.github/workflows/verify-action-pins.yml +16 -0
- data/.gitignore +4 -1
- data/.rspec +3 -1
- data/.rubocop.yml +6 -1
- data/.ruby-version +1 -0
- data/.yard-lint.yml +279 -0
- data/CHANGELOG.md +308 -139
- data/Gemfile +1 -8
- data/Gemfile.lint +9 -0
- data/Gemfile.lint.lock +69 -0
- data/README.md +16 -33
- data/Rakefile +6 -10
- data/bin/clean_sqs +52 -0
- data/bin/cli/base.rb +22 -2
- data/bin/cli/sqs.rb +74 -7
- data/bin/integrations +275 -0
- data/bin/scenario +154 -0
- data/bin/shoryuken +3 -2
- data/docker-compose.yml +6 -0
- data/lib/{shoryuken/extensions/active_job_extensions.rb → active_job/extensions.rb} +20 -6
- 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 +11 -1
- data/lib/shoryuken/client.rb +16 -0
- data/lib/shoryuken/default_exception_handler.rb +11 -0
- data/lib/shoryuken/default_worker_registry.rb +39 -11
- data/lib/shoryuken/environment_loader.rb +85 -15
- data/lib/shoryuken/errors.rb +36 -0
- data/lib/shoryuken/fetcher.rb +41 -3
- data/lib/shoryuken/helpers/atomic_boolean.rb +58 -0
- data/lib/shoryuken/helpers/atomic_counter.rb +104 -0
- data/lib/shoryuken/helpers/atomic_hash.rb +182 -0
- data/lib/shoryuken/helpers/hash_utils.rb +56 -0
- data/lib/shoryuken/helpers/string_utils.rb +65 -0
- data/lib/shoryuken/helpers/timer_task.rb +80 -0
- data/lib/shoryuken/inline_message.rb +22 -0
- data/lib/shoryuken/launcher.rb +55 -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 +43 -15
- data/lib/shoryuken/manager.rb +84 -5
- data/lib/shoryuken/message.rb +116 -1
- data/lib/shoryuken/middleware/chain.rb +141 -43
- data/lib/shoryuken/middleware/entry.rb +30 -0
- data/lib/shoryuken/middleware/server/active_record.rb +10 -0
- data/lib/shoryuken/middleware/server/auto_delete.rb +12 -0
- data/lib/shoryuken/middleware/server/auto_extend_visibility.rb +37 -11
- data/lib/shoryuken/middleware/server/exponential_backoff_retry.rb +34 -3
- data/lib/shoryuken/middleware/server/non_retryable_exception.rb +95 -0
- data/lib/shoryuken/middleware/server/timing.rb +13 -0
- data/lib/shoryuken/options.rb +154 -13
- data/lib/shoryuken/polling/base_strategy.rb +127 -0
- data/lib/shoryuken/polling/queue_configuration.rb +103 -0
- data/lib/shoryuken/polling/strict_priority.rb +41 -0
- data/lib/shoryuken/polling/weighted_round_robin.rb +44 -0
- data/lib/shoryuken/processor.rb +37 -3
- data/lib/shoryuken/queue.rb +99 -8
- data/lib/shoryuken/runner.rb +54 -16
- data/lib/shoryuken/util.rb +32 -7
- data/lib/shoryuken/version.rb +4 -1
- data/lib/shoryuken/worker/default_executor.rb +23 -1
- data/lib/shoryuken/worker/inline_executor.rb +33 -2
- data/lib/shoryuken/worker.rb +224 -0
- data/lib/shoryuken/worker_registry.rb +35 -0
- data/lib/shoryuken.rb +27 -38
- data/renovate.json +62 -0
- data/shoryuken.gemspec +8 -4
- 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/keyword_arguments/keyword_arguments_spec.rb +63 -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/custom_group_polling_strategy/custom_group_polling_strategy_spec.rb +87 -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/non_retryable_exception/non_retryable_exception_spec.rb +149 -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 +225 -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} +5 -4
- data/spec/{shoryuken/extensions/active_job_wrapper_spec.rb → lib/shoryuken/active_job/job_wrapper_spec.rb} +6 -5
- data/spec/{shoryuken → lib/shoryuken}/body_parser_spec.rb +2 -4
- data/spec/{shoryuken → lib/shoryuken}/client_spec.rb +1 -1
- data/spec/{shoryuken → lib/shoryuken}/default_exception_handler_spec.rb +9 -10
- data/spec/{shoryuken → lib/shoryuken}/default_worker_registry_spec.rb +1 -2
- data/spec/{shoryuken → lib/shoryuken}/environment_loader_spec.rb +10 -9
- data/spec/{shoryuken → lib/shoryuken}/fetcher_spec.rb +23 -26
- data/spec/lib/shoryuken/helpers/atomic_boolean_spec.rb +196 -0
- data/spec/lib/shoryuken/helpers/atomic_counter_spec.rb +177 -0
- data/spec/lib/shoryuken/helpers/atomic_hash_spec.rb +307 -0
- data/spec/lib/shoryuken/helpers/hash_utils_spec.rb +145 -0
- data/spec/lib/shoryuken/helpers/string_utils_spec.rb +124 -0
- data/spec/lib/shoryuken/helpers/timer_task_spec.rb +298 -0
- data/spec/lib/shoryuken/helpers_integration_spec.rb +96 -0
- data/spec/lib/shoryuken/inline_message_spec.rb +196 -0
- data/spec/{shoryuken → lib/shoryuken}/launcher_spec.rb +23 -2
- data/spec/lib/shoryuken/logging_spec.rb +242 -0
- data/spec/{shoryuken → lib/shoryuken}/manager_spec.rb +1 -2
- data/spec/lib/shoryuken/message_spec.rb +109 -0
- data/spec/{shoryuken → lib/shoryuken}/middleware/chain_spec.rb +1 -1
- 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_delete_spec.rb +1 -1
- data/spec/{shoryuken → lib/shoryuken}/middleware/server/auto_extend_visibility_spec.rb +51 -1
- data/spec/{shoryuken → lib/shoryuken}/middleware/server/exponential_backoff_retry_spec.rb +1 -1
- data/spec/lib/shoryuken/middleware/server/non_retryable_exception_spec.rb +214 -0
- data/spec/{shoryuken → lib/shoryuken}/middleware/server/timing_spec.rb +1 -1
- data/spec/{shoryuken → lib/shoryuken}/options_spec.rb +49 -6
- data/spec/lib/shoryuken/polling/base_strategy_spec.rb +280 -0
- data/spec/lib/shoryuken/polling/queue_configuration_spec.rb +195 -0
- data/spec/{shoryuken → lib/shoryuken}/polling/strict_priority_spec.rb +1 -1
- data/spec/{shoryuken → lib/shoryuken}/polling/weighted_round_robin_spec.rb +1 -1
- data/spec/{shoryuken → lib/shoryuken}/processor_spec.rb +1 -1
- data/spec/{shoryuken → lib/shoryuken}/queue_spec.rb +2 -3
- data/spec/{shoryuken → lib/shoryuken}/runner_spec.rb +1 -3
- data/spec/{shoryuken → lib/shoryuken}/util_spec.rb +2 -2
- data/spec/lib/shoryuken/version_spec.rb +17 -0
- data/spec/{shoryuken → lib/shoryuken}/worker/default_executor_spec.rb +1 -1
- data/spec/lib/shoryuken/worker/inline_executor_spec.rb +105 -0
- data/spec/lib/shoryuken/worker_registry_spec.rb +63 -0
- data/spec/{shoryuken → lib/shoryuken}/worker_spec.rb +15 -11
- data/spec/{shoryuken_spec.rb → lib/shoryuken_spec.rb} +1 -1
- data/spec/shared_examples_for_active_job.rb +40 -15
- data/spec/spec_helper.rb +48 -2
- metadata +295 -101
- data/.codeclimate.yml +0 -20
- data/.devcontainer/Dockerfile +0 -17
- data/.devcontainer/base.Dockerfile +0 -43
- data/.devcontainer/devcontainer.json +0 -35
- data/.github/FUNDING.yml +0 -12
- data/.github/dependabot.yml +0 -6
- data/.github/workflows/stale.yml +0 -20
- data/.reek.yml +0 -5
- data/Appraisals +0 -42
- data/gemfiles/.gitignore +0 -1
- data/gemfiles/aws_sdk_core_2.gemfile +0 -21
- data/gemfiles/rails_4_2.gemfile +0 -20
- data/gemfiles/rails_5_2.gemfile +0 -21
- data/gemfiles/rails_6_0.gemfile +0 -21
- data/gemfiles/rails_6_1.gemfile +0 -21
- data/gemfiles/rails_7_0.gemfile +0 -22
- data/lib/shoryuken/core_ext.rb +0 -69
- data/lib/shoryuken/extensions/active_job_adapter.rb +0 -103
- data/lib/shoryuken/extensions/active_job_concurrent_send_adapter.rb +0 -50
- data/lib/shoryuken/polling/base.rb +0 -67
- data/shoryuken.jpg +0 -0
- data/spec/integration/launcher_spec.rb +0 -128
- data/spec/shoryuken/core_ext_spec.rb +0 -40
- data/spec/shoryuken/extensions/active_job_adapter_spec.rb +0 -7
- data/spec/shoryuken/extensions/active_job_base_spec.rb +0 -84
- data/spec/shoryuken/worker/inline_executor_spec.rb +0 -49
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
require 'active_job'
|
|
5
|
+
|
|
6
|
+
# Skip this spec if ActiveSupport is not available, as the extensions require it
|
|
7
|
+
if defined?(ActiveSupport)
|
|
8
|
+
require 'active_job/extensions'
|
|
9
|
+
|
|
10
|
+
RSpec.describe Shoryuken::ActiveJob do
|
|
11
|
+
describe Shoryuken::ActiveJob::SQSSendMessageParametersAccessor do
|
|
12
|
+
let(:job_class) do
|
|
13
|
+
Class.new do
|
|
14
|
+
include Shoryuken::ActiveJob::SQSSendMessageParametersAccessor
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
let(:job_instance) { job_class.new }
|
|
19
|
+
|
|
20
|
+
describe 'included behavior' do
|
|
21
|
+
it 'adds sqs_send_message_parameters accessor' do
|
|
22
|
+
expect(job_instance).to respond_to(:sqs_send_message_parameters)
|
|
23
|
+
expect(job_instance).to respond_to(:sqs_send_message_parameters=)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'allows setting and getting sqs_send_message_parameters' do
|
|
27
|
+
params = { message_group_id: 'group1', message_deduplication_id: 'dedup1' }
|
|
28
|
+
job_instance.sqs_send_message_parameters = params
|
|
29
|
+
expect(job_instance.sqs_send_message_parameters).to eq(params)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
describe Shoryuken::ActiveJob::SQSSendMessageParametersSupport do
|
|
35
|
+
let(:base_class) do
|
|
36
|
+
Class.new do
|
|
37
|
+
attr_accessor :sqs_send_message_parameters
|
|
38
|
+
|
|
39
|
+
def initialize(*arguments)
|
|
40
|
+
# Mock ActiveJob::Base initialization
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def enqueue(options = {})
|
|
44
|
+
# Mock ActiveJob::Base enqueue method that returns remaining options
|
|
45
|
+
options
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
let(:job_class) do
|
|
51
|
+
Class.new(base_class) do
|
|
52
|
+
prepend Shoryuken::ActiveJob::SQSSendMessageParametersSupport
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
describe '#initialize' do
|
|
57
|
+
it 'initializes sqs_send_message_parameters to empty hash' do
|
|
58
|
+
job = job_class.new('arg1', 'arg2')
|
|
59
|
+
expect(job.sqs_send_message_parameters).to eq({})
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it 'calls super with the provided arguments' do
|
|
63
|
+
expect_any_instance_of(base_class).to receive(:initialize).with('arg1', 'arg2')
|
|
64
|
+
job_class.new('arg1', 'arg2')
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it 'handles ruby2_keywords compatibility' do
|
|
68
|
+
# Test that ruby2_keywords is called if available
|
|
69
|
+
if respond_to?(:ruby2_keywords, true)
|
|
70
|
+
expect(job_class.method(:new)).to respond_to(:ruby2_keywords) if RUBY_VERSION >= '2.7'
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Regression test for https://github.com/ruby-shoryuken/shoryuken/issues/961
|
|
75
|
+
# ActiveJob with keyword arguments was broken in Shoryuken 7.0 because
|
|
76
|
+
# the SQSSendMessageParametersSupport module's initialize method did not
|
|
77
|
+
# properly forward keyword arguments using ruby2_keywords.
|
|
78
|
+
context 'with keyword arguments' do
|
|
79
|
+
let(:base_class_with_kwargs) do
|
|
80
|
+
Class.new do
|
|
81
|
+
attr_accessor :sqs_send_message_parameters
|
|
82
|
+
attr_reader :received_name, :received_count, :received_enabled
|
|
83
|
+
|
|
84
|
+
def initialize(name:, count:, enabled: false)
|
|
85
|
+
@received_name = name
|
|
86
|
+
@received_count = count
|
|
87
|
+
@received_enabled = enabled
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
let(:job_class_with_kwargs) do
|
|
93
|
+
Class.new(base_class_with_kwargs) do
|
|
94
|
+
prepend Shoryuken::ActiveJob::SQSSendMessageParametersSupport
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it 'properly forwards keyword arguments to the base class' do
|
|
99
|
+
job = job_class_with_kwargs.new(name: 'test_name', count: 42, enabled: true)
|
|
100
|
+
|
|
101
|
+
expect(job.received_name).to eq('test_name')
|
|
102
|
+
expect(job.received_count).to eq(42)
|
|
103
|
+
expect(job.received_enabled).to eq(true)
|
|
104
|
+
expect(job.sqs_send_message_parameters).to eq({})
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
it 'properly forwards keyword arguments with default values' do
|
|
108
|
+
job = job_class_with_kwargs.new(name: 'another_test', count: 10)
|
|
109
|
+
|
|
110
|
+
expect(job.received_name).to eq('another_test')
|
|
111
|
+
expect(job.received_count).to eq(10)
|
|
112
|
+
expect(job.received_enabled).to eq(false)
|
|
113
|
+
expect(job.sqs_send_message_parameters).to eq({})
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Regression test for https://github.com/ruby-shoryuken/shoryuken/issues/961
|
|
118
|
+
# Test with a mix of positional and keyword arguments
|
|
119
|
+
context 'with mixed positional and keyword arguments' do
|
|
120
|
+
let(:base_class_mixed) do
|
|
121
|
+
Class.new do
|
|
122
|
+
attr_accessor :sqs_send_message_parameters
|
|
123
|
+
attr_reader :received_id, :received_data, :received_options
|
|
124
|
+
|
|
125
|
+
def initialize(id, data, options: {})
|
|
126
|
+
@received_id = id
|
|
127
|
+
@received_data = data
|
|
128
|
+
@received_options = options
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
let(:job_class_mixed) do
|
|
134
|
+
Class.new(base_class_mixed) do
|
|
135
|
+
prepend Shoryuken::ActiveJob::SQSSendMessageParametersSupport
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
it 'properly forwards mixed arguments to the base class' do
|
|
140
|
+
job = job_class_mixed.new('job_id', { key: 'value' }, options: { retry: true })
|
|
141
|
+
|
|
142
|
+
expect(job.received_id).to eq('job_id')
|
|
143
|
+
expect(job.received_data).to eq({ key: 'value' })
|
|
144
|
+
expect(job.received_options).to eq({ retry: true })
|
|
145
|
+
expect(job.sqs_send_message_parameters).to eq({})
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
describe '#enqueue' do
|
|
151
|
+
let(:job_instance) { job_class.new }
|
|
152
|
+
|
|
153
|
+
it 'extracts SQS-specific options and merges them into sqs_send_message_parameters' do
|
|
154
|
+
options = {
|
|
155
|
+
wait: 5 * 60, # 5 minutes in seconds
|
|
156
|
+
message_attributes: { 'type' => 'important' },
|
|
157
|
+
message_system_attributes: { 'source' => 'api' },
|
|
158
|
+
message_deduplication_id: 'dedup123',
|
|
159
|
+
message_group_id: 'group456',
|
|
160
|
+
other_option: 'value'
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
remaining_options = job_instance.enqueue(options)
|
|
164
|
+
|
|
165
|
+
expect(job_instance.sqs_send_message_parameters).to eq({
|
|
166
|
+
message_attributes: { 'type' => 'important' },
|
|
167
|
+
message_system_attributes: { 'source' => 'api' },
|
|
168
|
+
message_deduplication_id: 'dedup123',
|
|
169
|
+
message_group_id: 'group456'
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
expect(remaining_options).to eq({
|
|
173
|
+
wait: 300,
|
|
174
|
+
other_option: 'value'
|
|
175
|
+
})
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
it 'handles empty options gracefully' do
|
|
179
|
+
remaining_options = job_instance.enqueue({})
|
|
180
|
+
expect(job_instance.sqs_send_message_parameters).to eq({})
|
|
181
|
+
expect(remaining_options).to eq({})
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
it 'merges new SQS options with existing ones' do
|
|
185
|
+
job_instance.sqs_send_message_parameters = { message_group_id: 'existing_group' }
|
|
186
|
+
|
|
187
|
+
options = { message_deduplication_id: 'new_dedup' }
|
|
188
|
+
job_instance.enqueue(options)
|
|
189
|
+
|
|
190
|
+
expect(job_instance.sqs_send_message_parameters).to eq({
|
|
191
|
+
message_group_id: 'existing_group',
|
|
192
|
+
message_deduplication_id: 'new_dedup'
|
|
193
|
+
})
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
it 'overwrites existing SQS options when the same key is provided' do
|
|
197
|
+
job_instance.sqs_send_message_parameters = { message_group_id: 'old_group' }
|
|
198
|
+
|
|
199
|
+
options = { message_group_id: 'new_group' }
|
|
200
|
+
job_instance.enqueue(options)
|
|
201
|
+
|
|
202
|
+
expect(job_instance.sqs_send_message_parameters).to eq({
|
|
203
|
+
message_group_id: 'new_group'
|
|
204
|
+
})
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
describe 'module constants' do
|
|
210
|
+
it 'defines SQSSendMessageParametersAccessor' do
|
|
211
|
+
expect(Shoryuken::ActiveJob::SQSSendMessageParametersAccessor).to be_a(Module)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
it 'defines SQSSendMessageParametersSupport' do
|
|
215
|
+
expect(Shoryuken::ActiveJob::SQSSendMessageParametersSupport).to be_a(Module)
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
else
|
|
220
|
+
RSpec.describe 'Shoryuken::ActiveJob (skipped - ActiveSupport not available)' do
|
|
221
|
+
it 'skips tests when ActiveSupport is not available' do
|
|
222
|
+
skip('ActiveSupport not available in test environment')
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'shared_examples_for_active_job'
|
|
4
|
+
require 'active_job/queue_adapters/shoryuken_adapter'
|
|
5
|
+
require 'active_support/core_ext/numeric/time'
|
|
6
|
+
|
|
7
|
+
RSpec.describe ActiveJob::QueueAdapters::ShoryukenAdapter do
|
|
8
|
+
include_examples 'active_job_adapters'
|
|
9
|
+
|
|
10
|
+
describe '#enqueue_after_transaction_commit?' do
|
|
11
|
+
it 'returns true to support Rails 7.2+ transaction commit behavior' do
|
|
12
|
+
adapter = described_class.new
|
|
13
|
+
expect(adapter.enqueue_after_transaction_commit?).to eq(true)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
describe '.instance' do
|
|
18
|
+
it 'returns the same instance (singleton pattern)' do
|
|
19
|
+
instance1 = described_class.instance
|
|
20
|
+
instance2 = described_class.instance
|
|
21
|
+
expect(instance1).to be(instance2)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it 'returns a ShoryukenAdapter instance' do
|
|
25
|
+
expect(described_class.instance).to be_a(described_class)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
require 'shared_examples_for_active_job'
|
|
3
|
-
require '
|
|
4
|
-
require '
|
|
4
|
+
require 'active_job/queue_adapters/shoryuken_adapter'
|
|
5
|
+
require 'active_job/queue_adapters/shoryuken_concurrent_send_adapter'
|
|
5
6
|
|
|
6
7
|
RSpec.describe ActiveJob::QueueAdapters::ShoryukenConcurrentSendAdapter do
|
|
7
8
|
include_examples 'active_job_adapters'
|
|
@@ -36,4 +37,4 @@ RSpec.describe ActiveJob::QueueAdapters::ShoryukenConcurrentSendAdapter do
|
|
|
36
37
|
subject.enqueue(job, options)
|
|
37
38
|
end
|
|
38
39
|
end
|
|
39
|
-
end
|
|
40
|
+
end
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
require 'active_job'
|
|
3
|
-
require '
|
|
4
|
-
require '
|
|
4
|
+
require 'active_job/extensions'
|
|
5
|
+
require 'active_job/queue_adapters/shoryuken_adapter'
|
|
5
6
|
|
|
6
|
-
RSpec.describe ActiveJob::
|
|
7
|
+
RSpec.describe Shoryuken::ActiveJob::JobWrapper do
|
|
7
8
|
subject { described_class.new }
|
|
8
9
|
|
|
9
10
|
describe '#perform' do
|
|
@@ -17,4 +18,4 @@ RSpec.describe ActiveJob::QueueAdapters::ShoryukenAdapter::JobWrapper do
|
|
|
17
18
|
subject.perform sqs_msg, job_hash
|
|
18
19
|
end
|
|
19
20
|
end
|
|
20
|
-
end
|
|
21
|
+
end
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
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,12 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# rubocop:disable Metrics/BlockLength
|
|
4
3
|
RSpec.describe Shoryuken::DefaultExceptionHandler do
|
|
5
4
|
class CustomErrorHandler
|
|
6
5
|
extend Shoryuken::Util
|
|
7
6
|
|
|
8
7
|
def self.call(_ex, queue, _msg)
|
|
9
|
-
logger.error("#{queue
|
|
8
|
+
logger.error("#{queue} failed to process the message")
|
|
10
9
|
end
|
|
11
10
|
end
|
|
12
11
|
|
|
@@ -38,31 +37,31 @@ RSpec.describe Shoryuken::DefaultExceptionHandler do
|
|
|
38
37
|
|
|
39
38
|
subject { Shoryuken::Processor.new(queue, sqs_msg) }
|
|
40
39
|
|
|
41
|
-
context
|
|
40
|
+
context 'with default handler' do
|
|
42
41
|
before do
|
|
43
42
|
Shoryuken.exception_handlers = described_class
|
|
44
43
|
end
|
|
45
44
|
|
|
46
|
-
it
|
|
45
|
+
it 'logs an error message' do
|
|
47
46
|
expect(Shoryuken::Logging.logger).to receive(:error).twice
|
|
48
47
|
|
|
49
|
-
allow_any_instance_of(TestWorker).to receive(:perform).and_raise(StandardError,
|
|
48
|
+
allow_any_instance_of(TestWorker).to receive(:perform).and_raise(StandardError, 'error')
|
|
50
49
|
allow(sqs_msg).to receive(:body)
|
|
51
50
|
|
|
52
51
|
expect { subject.process }.to raise_error(StandardError)
|
|
53
52
|
end
|
|
54
53
|
end
|
|
55
54
|
|
|
56
|
-
context
|
|
55
|
+
context 'with custom handler' do
|
|
57
56
|
before do
|
|
58
57
|
Shoryuken.exception_handlers = [described_class, CustomErrorHandler]
|
|
59
58
|
end
|
|
60
59
|
|
|
61
|
-
it
|
|
60
|
+
it 'logs default and custom error messages' do
|
|
62
61
|
expect(Shoryuken::Logging.logger).to receive(:error).twice
|
|
63
|
-
expect(Shoryuken::Logging.logger).to receive(:error).with(
|
|
62
|
+
expect(Shoryuken::Logging.logger).to receive(:error).with('default failed to process the message').once
|
|
64
63
|
|
|
65
|
-
allow_any_instance_of(TestWorker).to receive(:perform).and_raise(StandardError,
|
|
64
|
+
allow_any_instance_of(TestWorker).to receive(:perform).and_raise(StandardError, 'error')
|
|
66
65
|
allow(sqs_msg).to receive(:body)
|
|
67
66
|
|
|
68
67
|
expect { subject.process }.to raise_error(StandardError)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
require 'active_job'
|
|
3
4
|
|
|
4
5
|
RSpec.describe Shoryuken::EnvironmentLoader do
|
|
@@ -23,7 +24,7 @@ RSpec.describe Shoryuken::EnvironmentLoader do
|
|
|
23
24
|
context "when given queues don't exist" do
|
|
24
25
|
specify do
|
|
25
26
|
expect { subject.load }.to raise_error(
|
|
26
|
-
|
|
27
|
+
Shoryuken::Errors::QueueNotFoundError,
|
|
27
28
|
<<-MSG.gsub(/^\s+/, '')
|
|
28
29
|
The specified queue(s) stubbed_queue do not exist.
|
|
29
30
|
Try 'shoryuken sqs create QUEUE-NAME' for creating a queue with default settings.
|
|
@@ -63,7 +64,7 @@ RSpec.describe Shoryuken::EnvironmentLoader do
|
|
|
63
64
|
end
|
|
64
65
|
|
|
65
66
|
specify do
|
|
66
|
-
Shoryuken.options[:queues] = [
|
|
67
|
+
Shoryuken.options[:queues] = %w[queue1 queue2] # default queues
|
|
67
68
|
Shoryuken.options[:groups] = [['custom', { queues: ['queue3'], delay: 25 }]]
|
|
68
69
|
subject.load
|
|
69
70
|
|
|
@@ -124,11 +125,11 @@ RSpec.describe Shoryuken::EnvironmentLoader do
|
|
|
124
125
|
end
|
|
125
126
|
end
|
|
126
127
|
|
|
127
|
-
describe
|
|
128
|
-
let(:cli_queues) { {
|
|
129
|
-
let(:config_queues) { [[
|
|
128
|
+
describe '#setup_options' do
|
|
129
|
+
let(:cli_queues) { { 'queue1' => 10, 'queue2' => 20 } }
|
|
130
|
+
let(:config_queues) { [['queue1', 8], ['queue2', 4]] }
|
|
130
131
|
|
|
131
|
-
context
|
|
132
|
+
context 'when given queues through config and CLI' do
|
|
132
133
|
specify do
|
|
133
134
|
allow_any_instance_of(Shoryuken::EnvironmentLoader).to receive(:config_file_options).and_return({ queues: config_queues })
|
|
134
135
|
Shoryuken::EnvironmentLoader.setup_options(queues: cli_queues)
|
|
@@ -136,7 +137,7 @@ RSpec.describe Shoryuken::EnvironmentLoader do
|
|
|
136
137
|
end
|
|
137
138
|
end
|
|
138
139
|
|
|
139
|
-
context
|
|
140
|
+
context 'when given queues through config only' do
|
|
140
141
|
specify do
|
|
141
142
|
allow_any_instance_of(Shoryuken::EnvironmentLoader).to receive(:config_file_options).and_return({ queues: config_queues })
|
|
142
143
|
Shoryuken::EnvironmentLoader.setup_options({})
|
|
@@ -144,7 +145,7 @@ RSpec.describe Shoryuken::EnvironmentLoader do
|
|
|
144
145
|
end
|
|
145
146
|
end
|
|
146
147
|
|
|
147
|
-
context
|
|
148
|
+
context 'when given queues through CLI only' do
|
|
148
149
|
specify do
|
|
149
150
|
Shoryuken::EnvironmentLoader.setup_options(queues: cli_queues)
|
|
150
151
|
expect(Shoryuken.options[:queues]).to eq(cli_queues)
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
require 'shoryuken/manager'
|
|
3
|
-
require 'shoryuken/fetcher'
|
|
1
|
+
# frozen_string_literal: true
|
|
4
2
|
|
|
5
|
-
# rubocop:disable Metrics/BlockLength
|
|
6
3
|
RSpec.describe Shoryuken::Fetcher do
|
|
7
4
|
let(:queue) { instance_double('Shoryuken::Queue', fifo?: false) }
|
|
8
5
|
let(:queue_name) { 'default' }
|
|
@@ -29,17 +26,17 @@ RSpec.describe Shoryuken::Fetcher do
|
|
|
29
26
|
Shoryuken.sqs_client_receive_message_opts[group] = { wait_time_seconds: 10 }
|
|
30
27
|
|
|
31
28
|
expect(queue).to receive(:receive_messages).with({
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
29
|
+
wait_time_seconds: 10,
|
|
30
|
+
max_number_of_messages: limit,
|
|
31
|
+
message_attribute_names: ['All'],
|
|
32
|
+
attribute_names: ['All']
|
|
33
|
+
}).and_return([])
|
|
37
34
|
|
|
38
35
|
subject.fetch(queue_config, limit)
|
|
39
36
|
end
|
|
40
37
|
|
|
41
38
|
it 'logs debug only' do
|
|
42
|
-
# See https://github.com/
|
|
39
|
+
# See https://github.com/ruby-shoryuken/shoryuken/issues/435
|
|
43
40
|
logger = double 'logger'
|
|
44
41
|
|
|
45
42
|
allow(subject).to receive(:logger).and_return(logger)
|
|
@@ -63,10 +60,10 @@ RSpec.describe Shoryuken::Fetcher do
|
|
|
63
60
|
Shoryuken.sqs_client_receive_message_opts[queue_name] = { max_number_of_messages: 1 }
|
|
64
61
|
|
|
65
62
|
expect(queue).to receive(:receive_messages).with({
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
63
|
+
max_number_of_messages: 1,
|
|
64
|
+
message_attribute_names: ['All'],
|
|
65
|
+
attribute_names: ['All']
|
|
66
|
+
}).and_return([])
|
|
70
67
|
|
|
71
68
|
subject.fetch(queue_config, limit)
|
|
72
69
|
end
|
|
@@ -79,10 +76,10 @@ RSpec.describe Shoryuken::Fetcher do
|
|
|
79
76
|
Shoryuken.sqs_client_receive_message_opts[queue_name] = { max_number_of_messages: 20 }
|
|
80
77
|
|
|
81
78
|
expect(queue).to receive(:receive_messages).with({
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
79
|
+
max_number_of_messages: limit,
|
|
80
|
+
message_attribute_names: ['All'],
|
|
81
|
+
attribute_names: ['All']
|
|
82
|
+
}).and_return([])
|
|
86
83
|
|
|
87
84
|
subject.fetch(queue_config, limit)
|
|
88
85
|
end
|
|
@@ -94,8 +91,8 @@ RSpec.describe Shoryuken::Fetcher do
|
|
|
94
91
|
specify do
|
|
95
92
|
allow(Shoryuken::Client).to receive(:queues).with(queue_name).and_return(queue)
|
|
96
93
|
expect(queue).to receive(:receive_messages).with({
|
|
97
|
-
|
|
98
|
-
|
|
94
|
+
max_number_of_messages: described_class::FETCH_LIMIT, attribute_names: ['All'], message_attribute_names: ['All']
|
|
95
|
+
}).and_return([])
|
|
99
96
|
|
|
100
97
|
subject.fetch(queue_config, limit)
|
|
101
98
|
end
|
|
@@ -106,26 +103,26 @@ RSpec.describe Shoryuken::Fetcher do
|
|
|
106
103
|
let(:queue) { instance_double('Shoryuken::Queue', fifo?: true, name: queue_name) }
|
|
107
104
|
|
|
108
105
|
it 'polls one message at a time' do
|
|
109
|
-
# see https://github.com/
|
|
106
|
+
# see https://github.com/ruby-shoryuken/shoryuken/pull/530
|
|
110
107
|
|
|
111
108
|
allow(Shoryuken::Client).to receive(:queues).with(queue_name).and_return(queue)
|
|
112
109
|
expect(queue).to receive(:receive_messages).with({
|
|
113
|
-
|
|
114
|
-
|
|
110
|
+
max_number_of_messages: 1, attribute_names: ['All'], message_attribute_names: ['All']
|
|
111
|
+
}).and_return([])
|
|
115
112
|
|
|
116
113
|
subject.fetch(queue_config, limit)
|
|
117
114
|
end
|
|
118
115
|
|
|
119
116
|
context 'with batch=true' do
|
|
120
117
|
it 'polls the provided limit' do
|
|
121
|
-
# see https://github.com/
|
|
118
|
+
# see https://github.com/ruby-shoryuken/shoryuken/pull/530
|
|
122
119
|
|
|
123
120
|
allow(Shoryuken::Client).to receive(:queues).with(queue_name).and_return(queue)
|
|
124
121
|
allow(Shoryuken.worker_registry).to receive(:batch_receive_messages?).with(queue.name).and_return(true)
|
|
125
122
|
|
|
126
123
|
expect(queue).to receive(:receive_messages).with({
|
|
127
|
-
|
|
128
|
-
|
|
124
|
+
max_number_of_messages: limit, attribute_names: ['All'], message_attribute_names: ['All']
|
|
125
|
+
}).and_return([])
|
|
129
126
|
|
|
130
127
|
subject.fetch(queue_config, limit)
|
|
131
128
|
end
|