Skip to content

Send each message's custom headers on pooled S3 connections - #512

Open
pacmano1 wants to merge 1 commit into
OpenIntegrationEngine:mainfrom
pacmano1:fix/s3-custom-headers-per-message
Open

pacmano1 wants to merge 1 commit into
OpenIntegrationEngine:mainfrom
pacmano1:fix/s3-custom-headers-per-message

Conversation

@pacmano1

Copy link
Copy Markdown
Contributor

Closes #511.

The File Writer fills in ${...} variables in S3 custom headers for every message, but the pooled S3Connection kept the headers of the message that created the pool, so every later write sent the first message's values.

Change

  • FileDispatcher.send: after borrowing a connection, an S3 connection gets this message's headers.
  • S3Connection: keeps them in its own field (setCustomHeaders), which getCustomHeaders() uses when set. Not in schemeProps, because every connection in a pool shares the first message's S3SchemeProperties.
  • Nothing else changes: other schemes, the pool key, and the File Reader, which keeps its own headers.

Thread safety: Donkey clones the connector properties for each message, including a copy of the header map, and the pool hands a connection to one sender until it's returned, so the headers set on a borrowed connection belong to that sender's message.

Tests

How to verify

Needs an S3 bucket and credentials the engine can use, for example AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN and AWS_REGION in the engine's environment, with Use Default Credential Provider Chain on.

  1. New channel: Channel Reader source; source transformer JavaScript step $c('clinic', String(msg));; File Writer in S3 mode, S3 Bucket <bucket>/s3-headers, file name ${message.messageId}.txt, template ${message.rawData}; in Amazon S3 Advanced Settings, Custom HTTP Headers x-amz-meta-clinic = ${clinic} and x-test-id = ${message.messageId}.
  2. Deploy, then send clinic A and clinic B.
  3. aws s3api head-object --bucket <bucket> --key s3-headers/2.txt --query Metadata
    • Before: {"clinic": "clinic A", "x-test-id": "1"}
    • After: {"clinic": "clinic B", "x-test-id": "2"}

Live-tested against real S3 on Java 21, on top of #506 (AWS SDK 2.55.12), the SDK this will ship with. Before: 2.txt carried message 1's values, with Keep Connection Open on and off (also reproduced on main). After: every object carried its own message's values, with Keep Connection Open on and off, and with the destination queue on and 2 threads (6 messages).

Co-authored with Claude Code.

The File Writer fills in ${...} variables in the S3 custom headers for
every message, but the pooled S3Connection kept the headers of the
message that created it. The pool key is only the credentials and the
region, so every later message reused the first message's values.

The File Writer now hands the borrowed connection the current message's
headers before writing. They live on the connection, not in its
S3SchemeProperties, because every connection in a pool shares the
properties of the message that created the pool. A borrowed connection
belongs to one sender until it is returned, so this is safe with several
queue or processing threads. Other schemes and the File Reader are
unchanged.

Reported as NextGen Connect issue 5116.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Finnegan's Owner <44065187+pacmano1@users.noreply.github.com>
@mgaffigan

Copy link
Copy Markdown
Contributor

Can we test this in CI? s3mock or similar?

@github-actions

Copy link
Copy Markdown

Test Results

130 files  +1  130 suites  +1   3m 50s ⏱️ + 1m 26s
738 tests +1  738 ✅ +1  0 💤 ±0  0 ❌ ±0 
828 runs  +1  822 ✅ +1  6 💤 ±0  0 ❌ ±0 

Results for commit a86b5c3. ± Comparison against base commit 6d348a0.

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.

S3 File Writer: custom header values stick at the first message

2 participants