Skip to content

feat(aws-kinesis): cache assumed-role credentials to avoid STS throttling - #3909

Draft
mdkhan-tw wants to merge 1 commit into
mainfrom
mz-kinesis-assume-role-cache
Draft

feat(aws-kinesis): cache assumed-role credentials to avoid STS throttling#3909
mdkhan-tw wants to merge 1 commit into
mainfrom
mz-kinesis-assume-role-cache

Conversation

@mdkhan-tw

Copy link
Copy Markdown
Contributor

Problem

Under high TPS, the actions-aws-kinesis destination calls STS AssumeRole on every request — and each assumeRole() makes two STS calls (intermediary role → target role). This causes IAM AssumeRole throttling errors.

Fix

Adds an in-memory TTL cache in the shared AWS sts lib (lib/AWS/sts.ts, which is used only by aws-kinesis — the s3 destinations have their own copies), keyed by roleArn | externalId | region:

  • TTL from real expiry — uses the actual STS credential Expiration minus a 5-minute safety buffer, so credentials are never handed out about to expire mid-use. Falls back to 55 minutes if STS omits an expiration.
  • In-flight de-duplication — a burst of concurrent cache misses for the same key collapses into a single STS refresh, avoiding a thundering herd on cold start / expiry.

Net effect: STS calls drop from two per request to at most two per role per TTL window. assumeRole's public signature is unchanged, so send() and testAuthentication() need no changes.

Testing

Extended src/lib/AWS/__test__/index.test.ts:

  • Added a test-only cache reset (__clearAssumedRoleCacheForTests) in beforeEach since the cache is module-level.
  • New cases: cache reuse (no second STS call), no cross-role sharing, concurrent-miss collapsing to one refresh, and refresh-after-expiry.

Local run (jest 27, via package-local binary):

Test Suites: 3 passed, 3 total
Tests:       24 passed, 24 total

(7 sts lib tests + 17 aws-kinesis destination tests)

🤖 Generated with Claude Code

…ling

Under high TPS, aws-kinesis called STS AssumeRole on every request (twice:
intermediary role + target role), causing IAM AssumeRole throttling errors.

Add an in-memory TTL cache in the shared AWS sts lib (used only by
aws-kinesis), keyed by role ARN + external id + region:

- TTL derived from the actual STS credential Expiration minus a 5-minute
  safety buffer, falling back to 55 minutes when STS omits an expiration.
- In-flight refresh de-duplication so a burst of concurrent cache misses
  collapses into a single STS refresh (avoids thundering herd).

This reduces STS calls from two per request to at most two per role per TTL
window. assumeRole's public signature is unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@mdkhan-tw
mdkhan-tw requested a review from a team as a code owner July 29, 2026 10:50
Copilot AI review requested due to automatic review settings July 29, 2026 10:50

Copilot AI 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.

Pull request overview

Note

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Adds an in-memory, TTL-based cache for STS assumed-role credentials in the aws-kinesis STS helper to reduce AssumeRole call volume and prevent throttling under high throughput, with tests covering cache reuse and concurrency behavior.

Changes:

  • Implemented assumed-role credential caching keyed by role ARN + external ID + region, with TTL derived from STS expiration and an expiry safety buffer.
  • Added in-flight refresh de-duplication to collapse concurrent cache misses into a single refresh.
  • Extended Jest tests to reset module-level cache between cases and verify reuse/expiry/concurrency behaviors.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

File Description
packages/destination-actions/src/lib/AWS/sts.ts Introduces TTL cache + in-flight refresh de-duplication for assumeRole, and returns expiration metadata from STS calls.
packages/destination-actions/src/lib/AWS/test/index.test.ts Adds cache-reset hook and new test cases validating caching and concurrency semantics.

Comment on lines +59 to +63
// In-memory cache of assumed-role credentials, keyed by role ARN + external id + region.
// Under high TPS, calling STS AssumeRole on every request causes IAM throttling. Caching the
// assumed credentials until shortly before they expire keeps STS calls to (at most) one refresh
// per role per TTL window instead of one (well, two - intermediary + target) per request.
const assumedRoleCache = new Map<string, AssumedRoleCacheEntry>()
Comment on lines +76 to +77
const buildAssumedRoleCacheKey = (roleArn: string, externalId: string, region: string): string =>
`${roleArn}|${externalId}|${region}`
Comment on lines +79 to +83
// Exposed for tests to reset the in-memory caches between cases.
export const __clearAssumedRoleCacheForTests = (): void => {
assumedRoleCache.clear()
inflightRoleRefreshes.clear()
}
Comment on lines +204 to +211
const ttl = target.expiration
? target.expiration.getTime() - Date.now() - CREDENTIALS_EXPIRY_BUFFER_MS
: DEFAULT_CREDENTIALS_TTL_MS

return {
credentials: target.credentials,
expiresAt: Date.now() + Math.max(ttl, 0)
}
expect(second).toEqual(first)
})

it('does not share cache entries across different roles/regions', async () => {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants