|
| 1 | +# frozen_string_literal: true |
| 2 | + |
| 3 | +# This spec tests dead letter queue (DLQ) functionality. |
| 4 | +# When a message exceeds maxReceiveCount, it should be moved to the DLQ. |
| 5 | +# Note: This test doesn't use poll_queues_until because messages should fail |
| 6 | +# and be moved to DLQ rather than being successfully processed. |
| 7 | + |
| 8 | +setup_localstack |
| 9 | + |
| 10 | +main_queue_name = DT.queues[0] |
| 11 | +dlq_name = DT.queues[1] |
| 12 | + |
| 13 | +# Create the dead letter queue first |
| 14 | +create_test_queue(dlq_name) |
| 15 | + |
| 16 | +dlq_url = Shoryuken::Client.sqs.get_queue_url(queue_name: dlq_name).queue_url |
| 17 | +dlq_arn = Shoryuken::Client.sqs.get_queue_attributes( |
| 18 | + queue_url: dlq_url, |
| 19 | + attribute_names: ['QueueArn'] |
| 20 | +).attributes['QueueArn'] |
| 21 | + |
| 22 | +# Create main queue with redrive policy - move to DLQ after 2 receives |
| 23 | +redrive_policy = { maxReceiveCount: 2, deadLetterTargetArn: dlq_arn }.to_json |
| 24 | +create_test_queue(main_queue_name, attributes: { |
| 25 | + 'VisibilityTimeout' => '1', |
| 26 | + 'RedrivePolicy' => redrive_policy |
| 27 | +}) |
| 28 | + |
| 29 | +main_queue_url = Shoryuken::Client.sqs.get_queue_url(queue_name: main_queue_name).queue_url |
| 30 | + |
| 31 | +# Send a message |
| 32 | +Shoryuken::Client.sqs.send_message( |
| 33 | + queue_url: main_queue_url, |
| 34 | + message_body: 'dlq test message' |
| 35 | +) |
| 36 | + |
| 37 | +# Manually receive the message multiple times to trigger DLQ |
| 38 | +# maxReceiveCount = 2, so after 2 receives without deletion, it goes to DLQ |
| 39 | +3.times do |i| |
| 40 | + msgs = Shoryuken::Client.sqs.receive_message( |
| 41 | + queue_url: main_queue_url, |
| 42 | + max_number_of_messages: 1, |
| 43 | + wait_time_seconds: 3, |
| 44 | + attribute_names: ['ApproximateReceiveCount'] |
| 45 | + ).messages |
| 46 | + |
| 47 | + if msgs.any? |
| 48 | + receive_count = msgs.first.attributes['ApproximateReceiveCount'].to_i |
| 49 | + DT[:receives] << { attempt: i + 1, receive_count: receive_count } |
| 50 | + # Don't delete - let visibility timeout expire |
| 51 | + sleep 2 |
| 52 | + else |
| 53 | + DT[:receives] << { attempt: i + 1, no_message: true } |
| 54 | + break |
| 55 | + end |
| 56 | +end |
| 57 | + |
| 58 | +# Verify message was received at least twice |
| 59 | +actual_receives = DT[:receives].reject { |r| r[:no_message] } |
| 60 | +assert(actual_receives.size >= 2, "Message should have been received at least twice (was #{actual_receives.size})") |
| 61 | + |
| 62 | +# Wait for message to be moved to DLQ |
| 63 | +sleep 3 |
| 64 | + |
| 65 | +# Check that message is now in the DLQ |
| 66 | +dlq_messages = Shoryuken::Client.sqs.receive_message( |
| 67 | + queue_url: dlq_url, |
| 68 | + max_number_of_messages: 10, |
| 69 | + wait_time_seconds: 5, |
| 70 | + attribute_names: ['All'] |
| 71 | +).messages |
| 72 | + |
| 73 | +assert(dlq_messages.size >= 1, 'Message should have been moved to DLQ') |
| 74 | +assert_equal('dlq test message', dlq_messages.first.body) |
| 75 | + |
| 76 | +# Verify message is no longer in main queue |
| 77 | +main_attrs = Shoryuken::Client.sqs.get_queue_attributes( |
| 78 | + queue_url: main_queue_url, |
| 79 | + attribute_names: %w[ApproximateNumberOfMessages ApproximateNumberOfMessagesNotVisible] |
| 80 | +).attributes |
| 81 | +main_count = main_attrs['ApproximateNumberOfMessages'].to_i + |
| 82 | + main_attrs['ApproximateNumberOfMessagesNotVisible'].to_i |
| 83 | +assert_equal(0, main_count, 'Main queue should be empty after DLQ move') |
| 84 | + |
| 85 | +# Clean up DLQ message |
| 86 | +dlq_messages.each do |msg| |
| 87 | + Shoryuken::Client.sqs.delete_message( |
| 88 | + queue_url: dlq_url, |
| 89 | + receipt_handle: msg.receipt_handle |
| 90 | + ) |
| 91 | +end |
0 commit comments