Skip to content

Commit

Permalink
fix race condition in S3 Express identity cache (closes #1072)
Browse files Browse the repository at this point in the history
  • Loading branch information
jakob-keller committed Jan 16, 2024
1 parent 110b0a2 commit 477b838
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-16)
^^^^^^^^^^^^^^^^^^
* 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))

Check warning on line 372 in aiobotocore/utils.py

View check run for this annotation

Codecov / codecov/patch

aiobotocore/utils.py#L372

Added line #L372 was not covered by tests

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)

Check warning on line 379 in aiobotocore/utils.py

View check run for this annotation

Codecov / codecov/patch

aiobotocore/utils.py#L379

Added line #L379 was not covered by tests

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

0 comments on commit 477b838

Please sign in to comment.