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,149 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This spec tests the non_retryable_exception middleware functionality.
|
|
4
|
+
# When non_retryable_exceptions is configured, messages that raise those exceptions
|
|
5
|
+
# should be deleted immediately instead of being retried.
|
|
6
|
+
|
|
7
|
+
require 'timeout'
|
|
8
|
+
|
|
9
|
+
setup_sqs
|
|
10
|
+
|
|
11
|
+
# Reset DT state to prevent data leakage from previous tests
|
|
12
|
+
DT.clear
|
|
13
|
+
|
|
14
|
+
queue_name = DT.queue
|
|
15
|
+
create_test_queue(queue_name, attributes: { 'VisibilityTimeout' => '2' })
|
|
16
|
+
Shoryuken.add_group('default', 1)
|
|
17
|
+
Shoryuken.add_queue(queue_name, 1, 'default')
|
|
18
|
+
|
|
19
|
+
# Define custom exception classes for testing
|
|
20
|
+
InvalidInputError = Class.new(StandardError)
|
|
21
|
+
RecordNotFoundError = Class.new(StandardError)
|
|
22
|
+
RetryableError = Class.new(StandardError)
|
|
23
|
+
|
|
24
|
+
# Worker that handles non-retryable exceptions
|
|
25
|
+
non_retryable_worker = Class.new do
|
|
26
|
+
include Shoryuken::Worker
|
|
27
|
+
|
|
28
|
+
shoryuken_options auto_delete: false,
|
|
29
|
+
batch: false,
|
|
30
|
+
non_retryable_exceptions: [InvalidInputError, RecordNotFoundError]
|
|
31
|
+
|
|
32
|
+
def perform(sqs_msg, body)
|
|
33
|
+
receive_count = sqs_msg.attributes['ApproximateReceiveCount'].to_i
|
|
34
|
+
DT[:attempts] << { receive_count: receive_count, body: body }
|
|
35
|
+
|
|
36
|
+
case body
|
|
37
|
+
when 'non_retryable_invalid'
|
|
38
|
+
raise InvalidInputError, 'Invalid input data'
|
|
39
|
+
when 'non_retryable_not_found'
|
|
40
|
+
raise RecordNotFoundError, 'Record not found'
|
|
41
|
+
when 'retryable_error'
|
|
42
|
+
# Fail on first attempt, succeed on retry
|
|
43
|
+
if receive_count < 2
|
|
44
|
+
raise RetryableError, 'Temporary failure'
|
|
45
|
+
end
|
|
46
|
+
DT[:successful_processing] << { body: body, final_receive_count: receive_count }
|
|
47
|
+
sqs_msg.delete
|
|
48
|
+
when 'success'
|
|
49
|
+
DT[:successful_processing] << { body: body, final_receive_count: receive_count }
|
|
50
|
+
sqs_msg.delete
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
non_retryable_worker.get_shoryuken_options['queue'] = queue_name
|
|
56
|
+
Shoryuken.register_worker(queue_name, non_retryable_worker)
|
|
57
|
+
|
|
58
|
+
queue_url = Shoryuken::Client.sqs.get_queue_url(queue_name: queue_name).queue_url
|
|
59
|
+
|
|
60
|
+
# Start launcher once for all tests
|
|
61
|
+
launcher = Shoryuken::Launcher.new
|
|
62
|
+
launcher.start
|
|
63
|
+
|
|
64
|
+
begin
|
|
65
|
+
# Test 1: Non-retryable exception (InvalidInputError) should be deleted immediately
|
|
66
|
+
Shoryuken::Client.sqs.send_message(
|
|
67
|
+
queue_url: queue_url,
|
|
68
|
+
message_body: 'non_retryable_invalid'
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
# Wait for processing attempt
|
|
72
|
+
Timeout.timeout(10) { sleep 0.5 until DT[:attempts].size >= 1 }
|
|
73
|
+
|
|
74
|
+
# Verify it was only attempted once (not retried)
|
|
75
|
+
invalid_attempts = DT[:attempts].select { |a| a[:body] == 'non_retryable_invalid' }
|
|
76
|
+
assert_equal(1, invalid_attempts.size, 'Non-retryable exception should only be attempted once')
|
|
77
|
+
assert_equal(1, invalid_attempts.first[:receive_count], 'Should be first attempt')
|
|
78
|
+
|
|
79
|
+
# Wait a moment for deletion to complete
|
|
80
|
+
sleep 2
|
|
81
|
+
|
|
82
|
+
# Verify message was deleted - queue should be empty
|
|
83
|
+
attributes = Shoryuken::Client.sqs.get_queue_attributes(
|
|
84
|
+
queue_url: queue_url,
|
|
85
|
+
attribute_names: ['ApproximateNumberOfMessages', 'ApproximateNumberOfMessagesNotVisible']
|
|
86
|
+
).attributes
|
|
87
|
+
|
|
88
|
+
total_messages = attributes['ApproximateNumberOfMessages'].to_i +
|
|
89
|
+
attributes['ApproximateNumberOfMessagesNotVisible'].to_i
|
|
90
|
+
assert_equal(0, total_messages, 'Message with non-retryable exception should be deleted immediately')
|
|
91
|
+
|
|
92
|
+
# Test 2: Another non-retryable exception (RecordNotFoundError) should also be deleted immediately
|
|
93
|
+
Shoryuken::Client.sqs.send_message(
|
|
94
|
+
queue_url: queue_url,
|
|
95
|
+
message_body: 'non_retryable_not_found'
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
# Wait for processing attempt
|
|
99
|
+
Timeout.timeout(10) { sleep 0.5 until DT[:attempts].size >= 2 }
|
|
100
|
+
|
|
101
|
+
# Verify it was only attempted once
|
|
102
|
+
not_found_attempts = DT[:attempts].select { |a| a[:body] == 'non_retryable_not_found' }
|
|
103
|
+
assert_equal(1, not_found_attempts.size, 'Non-retryable exception should only be attempted once')
|
|
104
|
+
|
|
105
|
+
# Wait for deletion
|
|
106
|
+
sleep 2
|
|
107
|
+
|
|
108
|
+
# Verify queue is empty again
|
|
109
|
+
attributes = Shoryuken::Client.sqs.get_queue_attributes(
|
|
110
|
+
queue_url: queue_url,
|
|
111
|
+
attribute_names: ['ApproximateNumberOfMessages', 'ApproximateNumberOfMessagesNotVisible']
|
|
112
|
+
).attributes
|
|
113
|
+
|
|
114
|
+
total_messages = attributes['ApproximateNumberOfMessages'].to_i +
|
|
115
|
+
attributes['ApproximateNumberOfMessagesNotVisible'].to_i
|
|
116
|
+
assert_equal(0, total_messages, 'Message with non-retryable exception should be deleted immediately')
|
|
117
|
+
|
|
118
|
+
# Test 3: Retryable exception (not in non_retryable_exceptions list) should still retry
|
|
119
|
+
Shoryuken::Client.sqs.send_message(
|
|
120
|
+
queue_url: queue_url,
|
|
121
|
+
message_body: 'retryable_error'
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
# Wait for successful processing (after retry)
|
|
125
|
+
Timeout.timeout(15) { sleep 0.5 until DT[:successful_processing].size >= 1 }
|
|
126
|
+
|
|
127
|
+
# Verify it was retried
|
|
128
|
+
retryable_attempts = DT[:attempts].select { |a| a[:body] == 'retryable_error' }
|
|
129
|
+
assert(retryable_attempts.size >= 2, 'Retryable exception should be retried')
|
|
130
|
+
assert_equal(1, DT[:successful_processing].size, 'Message should eventually succeed after retry')
|
|
131
|
+
assert_equal('retryable_error', DT[:successful_processing].first[:body])
|
|
132
|
+
|
|
133
|
+
# Test 4: Successful message should process normally
|
|
134
|
+
Shoryuken::Client.sqs.send_message(
|
|
135
|
+
queue_url: queue_url,
|
|
136
|
+
message_body: 'success'
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
# Wait for successful processing
|
|
140
|
+
Timeout.timeout(10) { sleep 0.5 until DT[:successful_processing].size >= 2 }
|
|
141
|
+
|
|
142
|
+
# Verify successful processing
|
|
143
|
+
success_attempts = DT[:attempts].select { |a| a[:body] == 'success' }
|
|
144
|
+
assert_equal(1, success_attempts.size, 'Successful message should only be attempted once')
|
|
145
|
+
assert_equal(2, DT[:successful_processing].size, 'Both successful messages should be processed')
|
|
146
|
+
ensure
|
|
147
|
+
launcher.stop
|
|
148
|
+
end
|
|
149
|
+
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This spec tests polling strategies including WeightedRoundRobin (default)
|
|
4
|
+
# with multi-queue worker message distribution.
|
|
5
|
+
|
|
6
|
+
setup_sqs
|
|
7
|
+
|
|
8
|
+
queue_high = DT.queues[0]
|
|
9
|
+
queue_medium = DT.queues[1]
|
|
10
|
+
queue_low = DT.queues[2]
|
|
11
|
+
|
|
12
|
+
[queue_high, queue_medium, queue_low].each { |q| create_test_queue(q) }
|
|
13
|
+
|
|
14
|
+
Shoryuken.add_group('default', 1)
|
|
15
|
+
# Higher weight = higher priority
|
|
16
|
+
Shoryuken.add_queue(queue_high, 3, 'default')
|
|
17
|
+
Shoryuken.add_queue(queue_medium, 2, 'default')
|
|
18
|
+
Shoryuken.add_queue(queue_low, 1, 'default')
|
|
19
|
+
|
|
20
|
+
worker_class = Class.new do
|
|
21
|
+
include Shoryuken::Worker
|
|
22
|
+
|
|
23
|
+
shoryuken_options auto_delete: true, batch: false
|
|
24
|
+
|
|
25
|
+
def perform(sqs_msg, body)
|
|
26
|
+
queue = sqs_msg.queue_url.split('/').last
|
|
27
|
+
DT[:by_queue] << { queue: queue, body: body }
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
[queue_high, queue_medium, queue_low].each do |queue|
|
|
32
|
+
worker_class.get_shoryuken_options['queue'] = queue
|
|
33
|
+
Shoryuken.register_worker(queue, worker_class)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
Shoryuken::Client.queues(queue_high).send_message(message_body: 'high-msg')
|
|
37
|
+
Shoryuken::Client.queues(queue_medium).send_message(message_body: 'medium-msg')
|
|
38
|
+
Shoryuken::Client.queues(queue_low).send_message(message_body: 'low-msg')
|
|
39
|
+
|
|
40
|
+
sleep 1
|
|
41
|
+
|
|
42
|
+
poll_queues_until { DT[:by_queue].size >= 3 }
|
|
43
|
+
|
|
44
|
+
queues_with_messages = DT[:by_queue].map { |m| m[:queue] }.uniq
|
|
45
|
+
assert_equal(3, queues_with_messages.size)
|
|
46
|
+
assert_equal(3, DT[:by_queue].size)
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This spec tests Shoryuken::Queue operations including:
|
|
4
|
+
# - Queue initialization (by name, URL, and ARN)
|
|
5
|
+
# - Visibility timeout retrieval
|
|
6
|
+
# - FIFO queue detection
|
|
7
|
+
# - Batch message sending
|
|
8
|
+
# - Batch message deletion
|
|
9
|
+
|
|
10
|
+
setup_sqs
|
|
11
|
+
|
|
12
|
+
# Test 1: Queue initialization by name
|
|
13
|
+
queue_name = DT.uuid
|
|
14
|
+
create_test_queue(queue_name)
|
|
15
|
+
|
|
16
|
+
queue = Shoryuken::Queue.new(Shoryuken::Client.sqs, queue_name)
|
|
17
|
+
assert_equal(queue_name, queue.name)
|
|
18
|
+
assert(queue.url.include?(queue_name), "URL should contain queue name")
|
|
19
|
+
refute(queue.fifo?, "Standard queue should not be FIFO")
|
|
20
|
+
|
|
21
|
+
# Test 2: Queue initialization by URL
|
|
22
|
+
queue_url = queue.url
|
|
23
|
+
queue_by_url = Shoryuken::Queue.new(Shoryuken::Client.sqs, queue_url)
|
|
24
|
+
assert_equal(queue_name, queue_by_url.name)
|
|
25
|
+
assert_equal(queue_url, queue_by_url.url)
|
|
26
|
+
|
|
27
|
+
# Test 3: Visibility timeout retrieval
|
|
28
|
+
visibility_timeout = queue.visibility_timeout
|
|
29
|
+
assert(visibility_timeout.is_a?(Integer), "Visibility timeout should be an integer")
|
|
30
|
+
assert(visibility_timeout >= 0, "Visibility timeout should be non-negative")
|
|
31
|
+
|
|
32
|
+
# Test 4: FIFO queue detection
|
|
33
|
+
fifo_queue_name = "#{DT.uuid}.fifo"
|
|
34
|
+
create_fifo_queue(fifo_queue_name)
|
|
35
|
+
|
|
36
|
+
fifo_queue = Shoryuken::Queue.new(Shoryuken::Client.sqs, fifo_queue_name)
|
|
37
|
+
assert_equal(fifo_queue_name, fifo_queue.name)
|
|
38
|
+
assert(fifo_queue.fifo?, "FIFO queue should be detected as FIFO")
|
|
39
|
+
|
|
40
|
+
# Test 5: Send single message
|
|
41
|
+
send_result = queue.send_message(message_body: 'test message 1')
|
|
42
|
+
assert(send_result.message_id, "Send result should have message_id")
|
|
43
|
+
|
|
44
|
+
# Test 6: Send message with hash body (auto JSON serialization)
|
|
45
|
+
hash_body = { key: 'value', number: 42 }
|
|
46
|
+
send_result2 = queue.send_message(message_body: hash_body)
|
|
47
|
+
assert(send_result2.message_id, "Send result should have message_id for hash body")
|
|
48
|
+
|
|
49
|
+
# Test 7: Batch message sending
|
|
50
|
+
batch_result = queue.send_messages([
|
|
51
|
+
{ message_body: 'batch msg 1' },
|
|
52
|
+
{ message_body: 'batch msg 2' },
|
|
53
|
+
{ message_body: 'batch msg 3' }
|
|
54
|
+
])
|
|
55
|
+
assert_equal(3, batch_result.successful.size, "All 3 batch messages should succeed")
|
|
56
|
+
|
|
57
|
+
# Test 8: Receive messages
|
|
58
|
+
sleep 1 # Allow messages to become visible
|
|
59
|
+
received = queue.receive_messages(max_number_of_messages: 10)
|
|
60
|
+
assert(received.size > 0, "Should receive at least one message")
|
|
61
|
+
assert(received.first.is_a?(Shoryuken::Message), "Received items should be Message objects")
|
|
62
|
+
|
|
63
|
+
# Test 9: Batch message deletion
|
|
64
|
+
entries = received.map.with_index do |msg, idx|
|
|
65
|
+
{ id: idx.to_s, receipt_handle: msg.receipt_handle }
|
|
66
|
+
end
|
|
67
|
+
delete_result = queue.delete_messages(entries: entries)
|
|
68
|
+
refute(delete_result, "Delete should succeed without failures")
|
|
69
|
+
|
|
70
|
+
# Test 10: FIFO queue message sending with auto-generated attributes
|
|
71
|
+
fifo_send_result = fifo_queue.send_message(message_body: 'fifo test message')
|
|
72
|
+
assert(fifo_send_result.message_id, "FIFO send should have message_id")
|
|
73
|
+
assert(fifo_send_result.sequence_number, "FIFO send should have sequence_number")
|
|
74
|
+
|
|
75
|
+
# Test 11: Send message with delay
|
|
76
|
+
delayed_result = queue.send_message(
|
|
77
|
+
message_body: 'delayed message',
|
|
78
|
+
delay_seconds: 5
|
|
79
|
+
)
|
|
80
|
+
assert(delayed_result.message_id, "Delayed message should have message_id")
|
|
81
|
+
|
|
82
|
+
# Cleanup
|
|
83
|
+
delete_test_queue(queue_name)
|
|
84
|
+
delete_test_queue(fifo_queue_name)
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# ActiveJob adapter integration tests for Rails 7.2
|
|
4
|
+
|
|
5
|
+
setup_active_job
|
|
6
|
+
|
|
7
|
+
class EmailJob < ActiveJob::Base
|
|
8
|
+
queue_as :default
|
|
9
|
+
|
|
10
|
+
def perform(user_id, message)
|
|
11
|
+
{ user_id: user_id, message: message, sent_at: Time.current }
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class DataProcessingJob < ActiveJob::Base
|
|
16
|
+
queue_as :high_priority
|
|
17
|
+
|
|
18
|
+
def perform(data_file)
|
|
19
|
+
"Processed: #{data_file}"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
class SerializationJob < ActiveJob::Base
|
|
24
|
+
queue_as :default
|
|
25
|
+
|
|
26
|
+
def perform(complex_data)
|
|
27
|
+
complex_data.transform_values(&:upcase)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Test adapter setup
|
|
32
|
+
adapter = ActiveJob::Base.queue_adapter
|
|
33
|
+
assert_equal("ActiveJob::QueueAdapters::ShoryukenAdapter", adapter.class.name)
|
|
34
|
+
|
|
35
|
+
# Test singleton pattern
|
|
36
|
+
instance1 = ActiveJob::QueueAdapters::ShoryukenAdapter.instance
|
|
37
|
+
instance2 = ActiveJob::QueueAdapters::ShoryukenAdapter.instance
|
|
38
|
+
assert_equal(instance1.object_id, instance2.object_id)
|
|
39
|
+
|
|
40
|
+
# Test transaction commit hook (Rails 7.2+)
|
|
41
|
+
adapter_instance = ActiveJob::QueueAdapters::ShoryukenAdapter.new
|
|
42
|
+
assert(adapter_instance.respond_to?(:enqueue_after_transaction_commit?))
|
|
43
|
+
assert_equal(true, adapter_instance.enqueue_after_transaction_commit?)
|
|
44
|
+
|
|
45
|
+
# Test simple job enqueue
|
|
46
|
+
job_capture = JobCapture.new
|
|
47
|
+
job_capture.start_capturing
|
|
48
|
+
|
|
49
|
+
EmailJob.perform_later(1, 'Hello World')
|
|
50
|
+
|
|
51
|
+
assert_equal(1, job_capture.job_count)
|
|
52
|
+
job = job_capture.last_job
|
|
53
|
+
message_body = job[:message_body]
|
|
54
|
+
assert_equal('EmailJob', message_body['job_class'])
|
|
55
|
+
assert_equal([1, 'Hello World'], message_body['arguments'])
|
|
56
|
+
assert_equal('default', message_body['queue_name'])
|
|
57
|
+
|
|
58
|
+
# Test different queue
|
|
59
|
+
job_capture2 = JobCapture.new
|
|
60
|
+
job_capture2.start_capturing
|
|
61
|
+
|
|
62
|
+
DataProcessingJob.perform_later('large_dataset.csv')
|
|
63
|
+
|
|
64
|
+
job2 = job_capture2.last_job
|
|
65
|
+
message_body2 = job2[:message_body]
|
|
66
|
+
assert_equal('DataProcessingJob', message_body2['job_class'])
|
|
67
|
+
assert_equal('high_priority', message_body2['queue_name'])
|
|
68
|
+
|
|
69
|
+
# Test complex data serialization
|
|
70
|
+
complex_data = {
|
|
71
|
+
'user' => { 'name' => 'John', 'age' => 30 },
|
|
72
|
+
'preferences' => ['email', 'sms']
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
job_capture3 = JobCapture.new
|
|
76
|
+
job_capture3.start_capturing
|
|
77
|
+
|
|
78
|
+
SerializationJob.perform_later(complex_data)
|
|
79
|
+
|
|
80
|
+
job3 = job_capture3.last_job
|
|
81
|
+
message_body3 = job3[:message_body]
|
|
82
|
+
args_data = message_body3['arguments'].first
|
|
83
|
+
assert_equal('John', args_data['user']['name'])
|
|
84
|
+
assert_equal(30, args_data['user']['age'])
|
|
85
|
+
|
|
86
|
+
# Test shoryuken_class message attribute
|
|
87
|
+
job_capture4 = JobCapture.new
|
|
88
|
+
job_capture4.start_capturing
|
|
89
|
+
|
|
90
|
+
EmailJob.perform_later(1, 'Attributes test')
|
|
91
|
+
|
|
92
|
+
job4 = job_capture4.last_job
|
|
93
|
+
attributes = job4[:message_attributes]
|
|
94
|
+
expected_shoryuken_class = {
|
|
95
|
+
string_value: "Shoryuken::ActiveJob::JobWrapper",
|
|
96
|
+
data_type: 'String'
|
|
97
|
+
}
|
|
98
|
+
assert_equal(expected_shoryuken_class, attributes['shoryuken_class'])
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# ActiveJob adapter integration tests for Rails 8.0
|
|
4
|
+
|
|
5
|
+
setup_active_job
|
|
6
|
+
|
|
7
|
+
class EmailJob < ActiveJob::Base
|
|
8
|
+
queue_as :default
|
|
9
|
+
|
|
10
|
+
def perform(user_id, message)
|
|
11
|
+
{ user_id: user_id, message: message, sent_at: Time.current }
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class DataProcessingJob < ActiveJob::Base
|
|
16
|
+
queue_as :high_priority
|
|
17
|
+
|
|
18
|
+
def perform(data_file)
|
|
19
|
+
"Processed: #{data_file}"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
class SerializationJob < ActiveJob::Base
|
|
24
|
+
queue_as :default
|
|
25
|
+
|
|
26
|
+
def perform(complex_data)
|
|
27
|
+
complex_data.transform_values(&:upcase)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Test adapter setup
|
|
32
|
+
adapter = ActiveJob::Base.queue_adapter
|
|
33
|
+
assert_equal("ActiveJob::QueueAdapters::ShoryukenAdapter", adapter.class.name)
|
|
34
|
+
|
|
35
|
+
# Test singleton pattern
|
|
36
|
+
instance1 = ActiveJob::QueueAdapters::ShoryukenAdapter.instance
|
|
37
|
+
instance2 = ActiveJob::QueueAdapters::ShoryukenAdapter.instance
|
|
38
|
+
assert_equal(instance1.object_id, instance2.object_id)
|
|
39
|
+
|
|
40
|
+
# Test transaction commit hook
|
|
41
|
+
adapter_instance = ActiveJob::QueueAdapters::ShoryukenAdapter.new
|
|
42
|
+
assert(adapter_instance.respond_to?(:enqueue_after_transaction_commit?))
|
|
43
|
+
assert_equal(true, adapter_instance.enqueue_after_transaction_commit?)
|
|
44
|
+
|
|
45
|
+
# Test simple job enqueue
|
|
46
|
+
job_capture = JobCapture.new
|
|
47
|
+
job_capture.start_capturing
|
|
48
|
+
|
|
49
|
+
EmailJob.perform_later(1, 'Hello World')
|
|
50
|
+
|
|
51
|
+
assert_equal(1, job_capture.job_count)
|
|
52
|
+
job = job_capture.last_job
|
|
53
|
+
message_body = job[:message_body]
|
|
54
|
+
assert_equal('EmailJob', message_body['job_class'])
|
|
55
|
+
assert_equal([1, 'Hello World'], message_body['arguments'])
|
|
56
|
+
assert_equal('default', message_body['queue_name'])
|
|
57
|
+
|
|
58
|
+
# Test different queue
|
|
59
|
+
job_capture2 = JobCapture.new
|
|
60
|
+
job_capture2.start_capturing
|
|
61
|
+
|
|
62
|
+
DataProcessingJob.perform_later('large_dataset.csv')
|
|
63
|
+
|
|
64
|
+
job2 = job_capture2.last_job
|
|
65
|
+
message_body2 = job2[:message_body]
|
|
66
|
+
assert_equal('DataProcessingJob', message_body2['job_class'])
|
|
67
|
+
assert_equal('high_priority', message_body2['queue_name'])
|
|
68
|
+
|
|
69
|
+
# Test complex data serialization
|
|
70
|
+
complex_data = {
|
|
71
|
+
'user' => { 'name' => 'John', 'age' => 30 },
|
|
72
|
+
'preferences' => ['email', 'sms']
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
job_capture3 = JobCapture.new
|
|
76
|
+
job_capture3.start_capturing
|
|
77
|
+
|
|
78
|
+
SerializationJob.perform_later(complex_data)
|
|
79
|
+
|
|
80
|
+
job3 = job_capture3.last_job
|
|
81
|
+
message_body3 = job3[:message_body]
|
|
82
|
+
args_data = message_body3['arguments'].first
|
|
83
|
+
assert_equal('John', args_data['user']['name'])
|
|
84
|
+
assert_equal(30, args_data['user']['age'])
|
|
85
|
+
|
|
86
|
+
# Test shoryuken_class message attribute
|
|
87
|
+
job_capture4 = JobCapture.new
|
|
88
|
+
job_capture4.start_capturing
|
|
89
|
+
|
|
90
|
+
EmailJob.perform_later(1, 'Attributes test')
|
|
91
|
+
|
|
92
|
+
job4 = job_capture4.last_job
|
|
93
|
+
attributes = job4[:message_attributes]
|
|
94
|
+
expected_shoryuken_class = {
|
|
95
|
+
string_value: "Shoryuken::ActiveJob::JobWrapper",
|
|
96
|
+
data_type: 'String'
|
|
97
|
+
}
|
|
98
|
+
assert_equal(expected_shoryuken_class, attributes['shoryuken_class'])
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# ActiveJob Continuations integration tests for Rails 8.0+
|
|
4
|
+
# Tests the stopping? method and continuation timestamp handling
|
|
5
|
+
|
|
6
|
+
setup_active_job
|
|
7
|
+
|
|
8
|
+
# Skip if ActiveJob::Continuable is not available (Rails < 8.0)
|
|
9
|
+
unless defined?(ActiveJob::Continuable)
|
|
10
|
+
puts "Skipping continuation tests - ActiveJob::Continuable not available (requires Rails 8.0+)"
|
|
11
|
+
exit 0
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Test stopping? returns false when launcher is not initialized
|
|
15
|
+
adapter = ActiveJob::QueueAdapters::ShoryukenAdapter.new
|
|
16
|
+
assert_equal(false, adapter.stopping?)
|
|
17
|
+
|
|
18
|
+
# Test stopping? returns true when launcher is stopping
|
|
19
|
+
launcher = Shoryuken::Launcher.new
|
|
20
|
+
runner = Shoryuken::Runner.instance
|
|
21
|
+
runner.instance_variable_set(:@launcher, launcher)
|
|
22
|
+
|
|
23
|
+
adapter2 = ActiveJob::QueueAdapters::ShoryukenAdapter.new
|
|
24
|
+
assert_equal(false, adapter2.stopping?)
|
|
25
|
+
|
|
26
|
+
launcher.instance_variable_set(:@stopping, true)
|
|
27
|
+
assert_equal(true, adapter2.stopping?)
|
|
28
|
+
|
|
29
|
+
# Reset launcher state
|
|
30
|
+
launcher.instance_variable_set(:@stopping, false)
|
|
31
|
+
|
|
32
|
+
# Test past timestamps for continuation retries
|
|
33
|
+
job_capture = JobCapture.new
|
|
34
|
+
job_capture.start_capturing
|
|
35
|
+
|
|
36
|
+
class ContinuableTestJob < ActiveJob::Base
|
|
37
|
+
include ActiveJob::Continuable if defined?(ActiveJob::Continuable)
|
|
38
|
+
queue_as :default
|
|
39
|
+
def perform; end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
adapter3 = ActiveJob::QueueAdapters::ShoryukenAdapter.new
|
|
43
|
+
job = ContinuableTestJob.new
|
|
44
|
+
job.sqs_send_message_parameters = {}
|
|
45
|
+
|
|
46
|
+
past_timestamp = Time.current.to_f - 60
|
|
47
|
+
adapter3.enqueue_at(job, past_timestamp)
|
|
48
|
+
|
|
49
|
+
captured_job = job_capture.last_job
|
|
50
|
+
assert(captured_job[:delay_seconds] <= 0, "Past timestamp should result in immediate delivery")
|
|
51
|
+
|
|
52
|
+
# Test current timestamp
|
|
53
|
+
job_capture2 = JobCapture.new
|
|
54
|
+
job_capture2.start_capturing
|
|
55
|
+
|
|
56
|
+
job2 = ContinuableTestJob.new
|
|
57
|
+
job2.sqs_send_message_parameters = {}
|
|
58
|
+
|
|
59
|
+
current_timestamp = Time.current.to_f
|
|
60
|
+
adapter3.enqueue_at(job2, current_timestamp)
|
|
61
|
+
|
|
62
|
+
captured_job2 = job_capture2.last_job
|
|
63
|
+
delay = captured_job2[:delay_seconds]
|
|
64
|
+
assert(delay >= -1 && delay <= 1, "Current timestamp should have minimal delay")
|
|
65
|
+
|
|
66
|
+
# Test future timestamp
|
|
67
|
+
job_capture3 = JobCapture.new
|
|
68
|
+
job_capture3.start_capturing
|
|
69
|
+
|
|
70
|
+
job3 = ContinuableTestJob.new
|
|
71
|
+
job3.sqs_send_message_parameters = {}
|
|
72
|
+
|
|
73
|
+
future_timestamp = Time.current.to_f + 30
|
|
74
|
+
adapter3.enqueue_at(job3, future_timestamp)
|
|
75
|
+
|
|
76
|
+
captured_job3 = job_capture3.last_job
|
|
77
|
+
delay3 = captured_job3[:delay_seconds]
|
|
78
|
+
assert(delay3 > 0, "Future timestamp should have positive delay")
|
|
79
|
+
assert(delay3 <= 30, "Delay should not exceed scheduled time")
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# ActiveJob adapter integration tests for Rails 8.1
|
|
4
|
+
|
|
5
|
+
setup_active_job
|
|
6
|
+
|
|
7
|
+
class EmailJob < ActiveJob::Base
|
|
8
|
+
queue_as :default
|
|
9
|
+
|
|
10
|
+
def perform(user_id, message)
|
|
11
|
+
{ user_id: user_id, message: message, sent_at: Time.current }
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class DataProcessingJob < ActiveJob::Base
|
|
16
|
+
queue_as :high_priority
|
|
17
|
+
|
|
18
|
+
def perform(data_file)
|
|
19
|
+
"Processed: #{data_file}"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
class SerializationJob < ActiveJob::Base
|
|
24
|
+
queue_as :default
|
|
25
|
+
|
|
26
|
+
def perform(complex_data)
|
|
27
|
+
complex_data.transform_values(&:upcase)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Test adapter setup
|
|
32
|
+
adapter = ActiveJob::Base.queue_adapter
|
|
33
|
+
assert_equal("ActiveJob::QueueAdapters::ShoryukenAdapter", adapter.class.name)
|
|
34
|
+
|
|
35
|
+
# Test singleton pattern
|
|
36
|
+
instance1 = ActiveJob::QueueAdapters::ShoryukenAdapter.instance
|
|
37
|
+
instance2 = ActiveJob::QueueAdapters::ShoryukenAdapter.instance
|
|
38
|
+
assert_equal(instance1.object_id, instance2.object_id)
|
|
39
|
+
|
|
40
|
+
# Test transaction commit hook
|
|
41
|
+
adapter_instance = ActiveJob::QueueAdapters::ShoryukenAdapter.new
|
|
42
|
+
assert(adapter_instance.respond_to?(:enqueue_after_transaction_commit?))
|
|
43
|
+
assert_equal(true, adapter_instance.enqueue_after_transaction_commit?)
|
|
44
|
+
|
|
45
|
+
# Test simple job enqueue
|
|
46
|
+
job_capture = JobCapture.new
|
|
47
|
+
job_capture.start_capturing
|
|
48
|
+
|
|
49
|
+
EmailJob.perform_later(1, 'Hello World')
|
|
50
|
+
|
|
51
|
+
assert_equal(1, job_capture.job_count)
|
|
52
|
+
job = job_capture.last_job
|
|
53
|
+
message_body = job[:message_body]
|
|
54
|
+
assert_equal('EmailJob', message_body['job_class'])
|
|
55
|
+
assert_equal([1, 'Hello World'], message_body['arguments'])
|
|
56
|
+
assert_equal('default', message_body['queue_name'])
|
|
57
|
+
|
|
58
|
+
# Test different queue
|
|
59
|
+
job_capture2 = JobCapture.new
|
|
60
|
+
job_capture2.start_capturing
|
|
61
|
+
|
|
62
|
+
DataProcessingJob.perform_later('large_dataset.csv')
|
|
63
|
+
|
|
64
|
+
job2 = job_capture2.last_job
|
|
65
|
+
message_body2 = job2[:message_body]
|
|
66
|
+
assert_equal('DataProcessingJob', message_body2['job_class'])
|
|
67
|
+
assert_equal('high_priority', message_body2['queue_name'])
|
|
68
|
+
|
|
69
|
+
# Test complex data serialization
|
|
70
|
+
complex_data = {
|
|
71
|
+
'user' => { 'name' => 'John', 'age' => 30 },
|
|
72
|
+
'preferences' => ['email', 'sms']
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
job_capture3 = JobCapture.new
|
|
76
|
+
job_capture3.start_capturing
|
|
77
|
+
|
|
78
|
+
SerializationJob.perform_later(complex_data)
|
|
79
|
+
|
|
80
|
+
job3 = job_capture3.last_job
|
|
81
|
+
message_body3 = job3[:message_body]
|
|
82
|
+
args_data = message_body3['arguments'].first
|
|
83
|
+
assert_equal('John', args_data['user']['name'])
|
|
84
|
+
assert_equal(30, args_data['user']['age'])
|
|
85
|
+
|
|
86
|
+
# Test shoryuken_class message attribute
|
|
87
|
+
job_capture4 = JobCapture.new
|
|
88
|
+
job_capture4.start_capturing
|
|
89
|
+
|
|
90
|
+
EmailJob.perform_later(1, 'Attributes test')
|
|
91
|
+
|
|
92
|
+
job4 = job_capture4.last_job
|
|
93
|
+
attributes = job4[:message_attributes]
|
|
94
|
+
expected_shoryuken_class = {
|
|
95
|
+
string_value: "Shoryuken::ActiveJob::JobWrapper",
|
|
96
|
+
data_type: 'String'
|
|
97
|
+
}
|
|
98
|
+
assert_equal(expected_shoryuken_class, attributes['shoryuken_class'])
|