Skip to content

Match requested message attribute names exactly or by prefix in ReceiveMessage - #1268

Merged
micossow merged 3 commits into
softwaremill:masterfrom
wleeaf:fix-message-attribute-name-filter
Nov 2, 2026
Merged

micossow merged 3 commits into
softwaremill:masterfrom
wleeaf:fix-message-attribute-name-filter

Conversation

@wleeaf

@wleeaf wleeaf commented Oct 25, 2026

Copy link
Copy Markdown
Contributor

ReceiveMessage picks the message attributes to return with k.r.findFirstIn(s). That treats each attribute name k as a regular expression and searches for it inside the requested name s. Two things go wrong:

  • An exact name also returns every attribute whose name occurs inside it. Asking for foo returns foo, fo and o, and asking for xay returns x.y, because the . matches any character.
  • A prefix such as foo.* doesn't return foo.bar or foo.baz, since a name that is longer than the request can't be found inside it. Instead it returns foo, fo and o.

The SQS docs for MessageAttributeNames say you can ask for attributes by name, use All or .* for all of them, or "use all message attributes starting with a prefix, for example bar.*".

With attributes foo, foo.bar, foo.baz, fo and o on one message:

MessageAttributeNames before after
foo foo, fo, o foo
foo.* foo, fo, o foo.bar, foo.baz

MD5OfMessageAttributes is computed from the filtered map, so it changes with it.

The fix keeps an attribute when its name equals a requested name, or when a requested name ends in .* and the attribute name starts with what comes before the *. All and .* work as before.

Test: a new case in MessageAttributesTests receives the same message once by exact name and once by prefix. It runs in both the SDK v1 and v2 suites, fails before the fix (Set("foo", "fo", "o") was not equal to Set("foo")) and passes after. scalafmtCheckAll, restSqs/test (28 tests) and restSqsTestingAmazonJavaSdk/test (162 tests) pass on Scala 2.13.

Copilot AI balanced review requested due to automatic review settings October 25, 2026 00:43

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing. Review the Copilot code review billing settings.

@micossow micossow left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the clear write-up and the before/after table. Looks good to me.

Correctness

  • The old filter k.r.findFirstIn(s) has been there since #97 (2017). It treated each stored attribute name as a regex and searched for it inside the requested name, so the matching ran the wrong way round. The new logic (exact match, or s.endsWith(".*") && k.startsWith(s.dropRight(1))) matches what the SQS docs describe for MessageAttributeNames. All and .* still short-circuit before the filter, so they behave as before.
  • Because s.dropRight(1) keeps the trailing ., foo.* matches foo.bar but not foo or foobar. That is the right reading of "starting with a prefix, for example bar.*".
  • MD5OfMessageAttributes is computed from the filtered map, so it stays consistent with the attributes that are returned.
  • I checked the existing helpers in IntegrationTestsBase (filterBasedOnRequestedAttributes). They already assume exact-name matching, so no existing test depended on the old substring behaviour.

Nits (non-blocking)

  • s.stripSuffix("*") might read a little more clearly than s.dropRight(1) next to the endsWith(".*") guard. Up to you.
  • In the test, byName.head and byPrefix.head throw a bare NoSuchElementException if nothing is received. Adding byName should have size 1 first would give a clearer failure message.

Note

  • No CI checks have run on this branch yet. Workflows for fork PRs probably need a maintainer to approve them before they run, so we should get a green run before merging.

@wleeaf

wleeaf commented Nov 2, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the review. Both nits are in 99aba8a: s.stripSuffix("*") for the prefix, and should have size 1 on both receives before .head. The attribute tests in AmazonJavaSdkV1TestSuite and AmazonJavaSdkV2TestSuite (34) pass, and scalafmtCheck is clean for both modules.

On CI: the failing job on the merge commit is ci-docker, in the "Build UI docker image" step. Next.js can't resolve @vercel/turbopack-next/internal/font/google/font, which happens when the build can't fetch Google Fonts. It doesn't touch the Scala code, and the test jobs (ci-2-12, ci-2-13, ci-3, ci-ui) passed. ci-docker also failed on #1267 on 2026-10-23 with a network timeout, so a rerun should clear it.

@micossow
micossow merged commit 2713746 into softwaremill:master Nov 2, 2026
25 of 26 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants