Skip to content

Commit c1cc348

Browse files
committed
fix: correctly deduplicate S3 Express credential cache refreshes
1 parent e5dd948 commit c1cc348

File tree

3 files changed

+17
-2
lines changed

3 files changed

+17
-2
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"id": "903848fb-77d4-4431-8a4e-abb52b25b7c8",
3+
"type": "bugfix",
4+
"description": "Fix concurrency issues with S3 Express credential caching"
5+
}

services/s3/common/src/aws/sdk/kotlin/services/s3/express/DefaultS3ExpressCredentialsProvider.kt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,18 @@ internal class DefaultS3ExpressCredentialsProvider(
5757
client.logger.trace { "Credentials for ${key.bucket} are expiring in ${it.expiringCredentials.expiresAt} and are within their refresh window, performing asynchronous refresh..." }
5858
launch(coroutineContext) {
5959
try {
60-
it.sfg.singleFlight { createSessionCredentials(key, client) }
60+
it.sfg.singleFlight {
61+
// This coroutine/SFG may have started _after_ prior instances(s) finished, replacing
62+
// the cached value already. To prevent re-refreshing it, we need to re-acquire the
63+
// current cached value and verify whether it's expiring soon.
64+
val currentCreds = credentialsCache.get(key)
65+
66+
if (currentCreds?.expiringCredentials?.isExpiringWithin(refreshBuffer) == true) {
67+
createSessionCredentials(key, client)
68+
} else {
69+
it.expiringCredentials
70+
}
71+
}
6172
} catch (e: Exception) {
6273
client.logger.warn(e) { "Asynchronous refresh for ${key.bucket} failed." }
6374
}

services/s3/common/test/aws/sdk/kotlin/services/s3/express/DefaultS3ExpressCredentialsProviderTest.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,6 @@ class DefaultS3ExpressCredentialsProviderTest {
116116
}
117117

118118
@Test
119-
@Ignore // FIXME flaky test temporarily disabled to unblock preview builds
120119
fun testAsyncRefreshDebounce() = runTest {
121120
val timeSource = TestTimeSource()
122121
val clock = ManualClock()

0 commit comments

Comments
 (0)