Skip to content

GH-1143 Add IGNORE QueueNotFoundStrategy option for SQS#1640

Open
BK202503 wants to merge 1 commit into
awspring:mainfrom
BK202503:gh-1143-ignore-queue-not-found
Open

GH-1143 Add IGNORE QueueNotFoundStrategy option for SQS#1640
BK202503 wants to merge 1 commit into
awspring:mainfrom
BK202503:gh-1143-ignore-queue-not-found

Conversation

@BK202503

Copy link
Copy Markdown

Closes #1143.

What

Adds a third option to QueueNotFoundStrategyIGNORE — that logs a warning and skips starting the listener container's message source when its queue does not exist, so application startup is not blocked. Subsequent polls for that source return empty.

This restores the default behavior of Spring Cloud AWS 2.x (spring-cloud-starter-aws-messaging) for users that rely on it during the 2.x → 3.x migration, as flagged by several commenters on #1143.

Why

Today the two strategies are:

  • FAIL — throws on a missing queue and blocks application startup. Wrong for deployments where the queue is legitimately optional.
  • CREATE — calls CreateQueue on a missing queue. Requires sqs:CreateQueue IAM and can interfere with externally-managed queue configuration / cross-team queue ownership.

Neither fits the case where a queue may legitimately be absent in some deployments (optional feature queues, multi-region rollout where the queue hasn't been created yet, etc.) and the listener should simply skip rather than crash the app.

@tomazfernandes wrote on the issue: "I don't have a solution in mind, but happy to take a look at a PR with a proposal." — this is that proposal.

How

The main concern from the issue was "graciously handle the error thrown by the QueueAttributesResolver and interrupting container startup". The patch routes that through a typed signal rather than reusing the generic resolver exception:

  • QueueNotFoundStrategy gets a new IGNORE constant with Javadoc that cross-references the 2.x default behavior.
  • QueueAttributesResolver.handleException, on QueueDoesNotExistException + IGNORE, logs a warning and fails the future with a new QueueNotFoundException (subtype of QueueAttributesResolvingException, so existing catch sites keep working; the dedicated subtype is what lets the source distinguish "ignore this queue" from a generic resolver failure). The CREATE path is unchanged.
  • QueueAttributesResolver.wrapException passes QueueNotFoundException through unwrapped instead of re-wrapping in QueueAttributesResolvingException, so the source sees the typed signal.
  • AbstractSqsMessageSource.doStart catches CompletionException with QueueNotFoundException as its cause, flips a skipped flag, logs a warning, and returns without setting queueAttributes / queueUrl or configuring the conversion context.
  • AbstractSqsMessageSource.doPollForMessages short-circuits to an empty future when skipped, so the polling loop is a no-op for the lifetime of the source.

The @RetryableTopic-style or FAIL paths are untouched — only the new IGNORE constant exercises the new branches. The property binding for spring.cloud.aws.sqs.queue-not-found-strategy=IGNORE picks up automatically because SqsProperties already exposes the enum directly.

Test plan

  • New QueueAttributesResolverIntegrationTests#shouldIgnoreQueueWhenStrategyIsIgnore mirrors the existing #shouldNotCreateQueue pattern against LocalStack, asserting that resolving a non-existent queue with IGNORE surfaces a QueueNotFoundException whose cause is QueueDoesNotExistException (rather than the generic QueueAttributesResolvingException that FAIL produces).
  • Full QueueAttributesResolverIntegrationTests class (7 tests) passes locally on LocalStack — the existing FAIL / CREATE paths still produce their original exception types because wrapException only passes through QueueNotFoundException specifically.
  • ./mvnw -B spotless:apply clean.

Docs

  • docs/src/main/asciidoc/sqs.adoc — the table entry for queueNotFoundStrategy gets a sentence on the IGNORE behavior next to the existing FAIL note.

AI agent disclosure

I used an AI coding agent (Claude Code) to navigate the existing strategy / resolver / source code paths and draft this patch. I have read every line, verified the dispatch through the CompletionException unwrap in doStart, traced the property-binding to confirm no SqsProperties change is needed, and confirmed the new IGNORE test passes against LocalStack alongside the existing 6 resolver tests. I will be the one responding to review.

Restore the Spring Cloud AWS 2.x behavior where a missing SQS queue at
listener startup did not fail the application context. In 3.x today the
two strategies are FAIL (throws on missing queue, blocks startup) and
CREATE (calls CreateQueue on missing, requires sqs:CreateQueue IAM and
can interfere with externally-managed queue configuration); neither
fits the common case where a queue may legitimately be absent in some
deployments — for example an optional feature queue, or a multi-region
rollout that hasn't created the queue yet.

Add a third strategy, IGNORE, that logs a warning and skips starting
the listener container's message source for that queue. Subsequent
polls return empty so the application keeps running cleanly.

Wiring:
- QueueNotFoundStrategy gets a new IGNORE constant with Javadoc that
  cross-references the 2.x default behavior.
- QueueAttributesResolver.handleException, on
  QueueDoesNotExistException + IGNORE, logs a warning and fails the
  future with a new QueueNotFoundException (subtype of
  QueueAttributesResolvingException so existing catch sites keep
  working; the dedicated subtype is what the source uses to recognize
  the IGNORE signal). The CREATE path is unchanged.
- QueueAttributesResolver.wrapException passes QueueNotFoundException
  through unwrapped instead of re-wrapping in
  QueueAttributesResolvingException, so the source sees the typed
  signal rather than a generic resolver failure.
- AbstractSqsMessageSource.doStart catches CompletionException with
  QueueNotFoundException as its cause, flips a `skipped` flag, logs a
  warning, and returns without setting queueAttributes/queueUrl or
  configuring the conversion context.
- AbstractSqsMessageSource.doPollForMessages short-circuits to an empty
  future when `skipped`, so the polling loop is a no-op for the
  lifetime of the source.

Tests:
- QueueAttributesResolverIntegrationTests#shouldIgnoreQueueWhenStrategyIsIgnore
  mirrors the existing #shouldNotCreateQueue pattern against LocalStack,
  asserting that resolving a non-existent queue with IGNORE surfaces a
  QueueNotFoundException whose cause is QueueDoesNotExistException
  (rather than the generic QueueAttributesResolvingException that FAIL
  produces).
- The full QueueAttributesResolverIntegrationTests class (7 tests)
  passes locally on LocalStack.

Docs:
- sqs.adoc table entry for queueNotFoundStrategy gets a sentence on
  the IGNORE behavior next to the existing FAIL note.

The property binding for `spring.cloud.aws.sqs.queue-not-found-strategy`
picks up IGNORE automatically because SqsProperties already exposes the
enum directly.

Closes awspring#1143.

Signed-off-by: BK202503 <199436087+BK202503@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component: sqs SQS integration related issue type: documentation Documentation or Samples related issue

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add IGNORE QueueNotFoundStrategy Option for SQS

1 participant