Skip to content

Commit

Permalink
fix race condition in S3 Express identity cache (closes #1072) (#1073)
Browse files Browse the repository at this point in the history
  • Loading branch information
jakob-keller authored Jan 17, 2024
1 parent 110b0a2 commit 7ea5c2f
Show file tree
Hide file tree
Showing 3 changed files with 9 additions and 19 deletions.
4 changes: 4 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
Changes
-------

2.9.1 (2024-01-17)
^^^^^^^^^^^^^^^^^^
* fix race condition in S3 Express identity cache #1072

2.9.0 (2023-12-12)
^^^^^^^^^^^^^^^^^^
* bump botocore dependency specification
Expand Down
2 changes: 1 addition & 1 deletion aiobotocore/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '2.9.0'
__version__ = '2.9.1'
22 changes: 4 additions & 18 deletions aiobotocore/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,30 +367,16 @@ async def get_credentials(self, **kwargs):


class AioS3ExpressIdentityCache(AioIdentityCache, S3ExpressIdentityCache):
@functools.cached_property
def _aio_credential_cache(self):
"""Substitutes upstream credential cache."""
return {}
@functools.lru_cache(maxsize=100)
def _get_credentials(self, bucket):
return asyncio.create_task(super().get_credentials(bucket=bucket))

async def get_credentials(self, bucket):
# upstream uses `@functools.lru_cache(maxsize=100)` to cache credentials.
# This is incompatible with async code.
# We need to implement custom caching logic.

if (credentials := self._aio_credential_cache.get(bucket)) is None:
# cache miss -> get credentials asynchronously
credentials = await super().get_credentials(bucket=bucket)

# upstream cache is bounded at 100 entries
if len(self._aio_credential_cache) >= 100:
# drop oldest entry from cache (deviates from lru_cache logic)
self._aio_credential_cache.pop(
next(iter(self._aio_credential_cache)),
)

self._aio_credential_cache[bucket] = credentials

return credentials
return await self._get_credentials(bucket=bucket)

def build_refresh_callback(self, bucket):
async def refresher():
Expand Down

0 comments on commit 7ea5c2f

Please sign in to comment.