Skip to content

Fix lock contention - #200

Merged
bob2681312 merged 2 commits into
masterfrom
fix-lock-contention
Jul 30, 2026
Merged

Fix lock contention#200
bob2681312 merged 2 commits into
masterfrom
fix-lock-contention

Conversation

@bob2681312

@bob2681312 bob2681312 commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Description

Why is this change being made?

  • To improve performance of the library, so that it can process retrieving many secrets concurrently

What is changing?

  • Changed locking from a global lock to a per-secret lock
  • Add locking when getting secrets from cache to resolve concurrency issues.
  • Changed TrimCacheToSizeLimit function in SecretCacheItem.cs to reference correct constant
  • In ISecretsManagerCache, convert GetCachedSecret method to an async method to be able to do proper locking.

Breaking: ISecretsManagerCache.GetCachedSecret signature changed from SecretCacheItem to Task<SecretCacheItem>. Implementers of the interface must update.


Testing

How was this tested?

dotnet test -f net8.0

Note: Some tests could not be run locally as they require running on Windows.


Reviewee Checklist

Update the checklist after submitting the PR

  • I have reviewed, tested and understand all changes
    If not, why:
  • I have filled out the Description and Testing sections above
    If not, why:
  • Build and Unit tests are passing
    If not, why:
  • Unit test coverage check is passing
    If not, why:
  • Integration tests pass locally
    If not, why:
  • I have updated integration tests (if needed)
    If not, why:
  • I have ensured no sensitive information is leaking (i.e., no logging of sensitive fields, or otherwise)
    If not, why:
  • I have added explanatory comments for complex logic, new classes/methods and new tests
    If not, why:
  • I have updated README/documentation (if needed)
    If not, why:
  • I have clearly called out breaking changes (if any)
    If not, why:

Reviewer Checklist

All reviewers please ensure the following are true before reviewing:

  • Reviewee checklist has been accurately filled out
  • Code changes align with stated purpose in description
  • Test coverage adequately validates the changes

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

@bob2681312
bob2681312 requested a review from a team as a code owner July 28, 2026 00:43
@secrets-manager-ai-code-review

This comment was marked as outdated.

Comment thread test/Amazon.SecretsManager.Extensions.Caching.UnitTests/CacheTests.cs Outdated
@bob2681312
bob2681312 marked this pull request as draft July 28, 2026 03:33
@bob2681312
bob2681312 force-pushed the fix-lock-contention branch from ab0dc35 to de7a7a8 Compare July 28, 2026 16:34
@secrets-manager-ai-code-review

This comment was marked as outdated.

@codecov

This comment was marked as outdated.

Comment thread src/Amazon.SecretsManager.Extensions.Caching/SecretsManagerCache.cs Outdated
Comment thread src/Amazon.SecretsManager.Extensions.Caching/SecretCacheObject.cs Outdated
Comment thread test/Amazon.SecretsManager.Extensions.Caching.UnitTests/CacheTests.cs Outdated
@secrets-manager-ai-code-review

This comment was marked as outdated.

Comment thread src/Amazon.SecretsManager.Extensions.Caching/SecretCacheItem.cs Outdated
Comment thread src/Amazon.SecretsManager.Extensions.Caching/SecretsManagerCache.cs Outdated
Comment thread src/Amazon.SecretsManager.Extensions.Caching/SecretsManagerCache.cs Outdated
@secrets-manager-ai-code-review

This comment was marked as outdated.

@bob2681312
bob2681312 marked this pull request as ready for review July 28, 2026 20:55
@secrets-manager-ai-code-review

This comment was marked as outdated.

@secrets-manager-ai-code-review

This comment was marked as outdated.

i-am-SR

This comment was marked as resolved.

@secrets-manager-ai-code-review

This comment was marked as outdated.

@secrets-manager-ai-code-review

This comment was marked as outdated.

Comment thread src/Amazon.SecretsManager.Extensions.Caching/SecretCacheItem.cs Outdated
@secrets-manager-ai-code-review

secrets-manager-ai-code-review Bot commented Jul 30, 2026

Copy link
Copy Markdown

Claude finished @bob2681312's task in 4m 49s —— View job


Review: Fix lock contention

  • Read changed files and prior review history
  • Analyze correctness of the locking changes
  • Attempt build/tests (see note)
  • Post review feedback

I re-reviewed the current state of the branch against the long thread of prior feedback. The substantive concurrency bugs raised earlier have all been addressed — this is now in good shape. A few minor items remain.

Note: I couldn't run dotnet build/dotnet test in this environment (sandbox permission denied). The analysis below is from reading the code. CI (dotnet.yml, Windows) is the source of truth for test results.


✅ Confirmed fixes since earlier reviews

  • Get-or-create race (SecretsManagerCache.GetCachedSecret): now double-checked — a lock-free cache.Get fast path, then cacheLock.WaitAsync outside the try, GetOrCreate + Compact inside the lock, Release() in finally. This closes the multi-instance race and keeps cache hits off the lock (addresses @reyhankoyun's hot-path concern).
  • Un-awaited WaitAsync in GetVersion: now awaited, wrapped in try/finally, acquire outside the try. SemaphoreFullException/no-exclusion bug resolved.
  • versions.Count check + TrimCacheToSizeLimit(): moved inside versionsLock, matching the item-cache pattern.
  • cancellationToken propagation: now threaded through GetSecretString/GetSecretBinary/RefreshNowAsyncGetCachedSecret, and GetVersion(result, cancellationToken).
  • refreshNeeded = true under objLock in RefreshNowAsync, and MAX_VERSIONS_CACHE_SIZE constant fix in TrimCacheToSizeLimit.

I also verified refreshNeeded is now read/written exclusively under objLock (RefreshAsync, RefreshNowAsync, IsRefreshNeeded), so its lack of volatile is no longer a visibility concern. GetVersion runs outside GetSecretValue's objLock (called after the finally at SecretCacheObject.cs:220), so reusing a separate versionsLock is self-deadlock-safe.

The two deterministic tests (ConcurrentGetSecretStringOnlyRefreshesOncedescribeCallCount == 1, ConcurrentRefreshNowDoesNotCorruptStaterefreshCount == 11) are now genuinely deterministic given the cacheLock/objLock serialization, not just usually-green.


🟡 Minor — remaining items

1. The [Trait("Category","Concurrency")] tests still run on every CI build.
Adding the trait was the right first step, but .github/workflows/dotnet.yml runs dotnet test with no filter, so nothing actually excludes the concurrency tests. To honor the earlier "gate them out of the default run" request, the test step would need e.g. --filter "Category!=Concurrency" (and a separate opt-in job to run them). Since they're now deterministic this is low-urgency, but as written the trait has no effect on CI.
(I can't modify files under .github/workflows/ — GitHub App permissions block workflow edits — so this one is for a maintainer.)

2. SemaphoreSlim / nested MemoryCache disposal (follow-up, acknowledged out-of-scope).
SecretsManagerCache.Dispose() disposes cache but not cacheLock; SecretCacheItem never disposes its versions MemoryCache, versionsLock, or the base objLock, and MemoryCache doesn't dispose evicted values. Under churn beyond MaxCacheSize this leaks. You marked this out-of-scope and I agree it needn't block the PR — worth a tracking issue since the nested MemoryCache makes it more material than a bare semaphore.

3. Doc nitSecretsManagerCache.cs:24 and ISecretsManagerCache.cs:22 both have the pre-existing typo "clide-side" (→ "client-side"). Not introduced here; trivial to fix while nearby.


Verdict

The core fix — per-secret SemaphoreSlim instead of a global lock, plus correctly-serialized cold-path creation — is sound and the earlier correctness blockers are resolved. Remaining items are minor/non-blocking. The breaking change to ISecretsManagerCache.GetCachedSecret (now Task<SecretCacheItem>) is correctly called out in the PR body; make sure it lands with an appropriate version bump.

Comment thread test/Amazon.SecretsManager.Extensions.Caching.UnitTests/CacheTests.cs Outdated
@bob2681312
bob2681312 enabled auto-merge (squash) July 30, 2026 20:53
@secrets-manager-ai-code-review

This comment was marked as resolved.

@bob2681312
bob2681312 merged commit 6703c71 into master Jul 30, 2026
6 checks passed
@bob2681312
bob2681312 deleted the fix-lock-contention branch July 30, 2026 21:52
simonmarty added a commit that referenced this pull request Aug 4, 2026
## Description

### Why is this change being made?

1. Bump the major version based on the git history since the last
release. The cache API is changing due to #200.


### What is changing?

1.


### Related Links
- **Issue #, if available**:

---

## Testing

### How was this tested?

1. 

### When testing locally, provide testing artifact(s):

1. 

---

## Reviewee Checklist

**Update the checklist after submitting the PR**

- [x] I have reviewed, tested and understand all changes
  *If not, why:*
- [x] I have filled out the Description and Testing sections above
  *If not, why:*
- [x] Build and Unit tests are passing
  *If not, why:*
- [x] Unit test coverage check is passing
  *If not, why:*
- [ ] Integration tests pass locally
  *If not, why:*
- [ ] I have updated integration tests (if needed)
  *If not, why:*
- [x] I have ensured no sensitive information is leaking (i.e., no
logging of sensitive fields, or otherwise)
  *If not, why:*
- [ ] I have added explanatory comments for complex logic, new
classes/methods and new tests
  *If not, why:*
- [ ] I have updated README/documentation (if needed)
  *If not, why:*
- [ ] I have clearly called out breaking changes (if any)
  *If not, why:*

---

## Reviewer Checklist

**All reviewers please ensure the following are true before reviewing:**

- Reviewee checklist has been accurately filled out
- Code changes align with stated purpose in description
- Test coverage adequately validates the changes

---

By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache 2.0 license.

---------

Signed-off-by: Simon Marty <simon.marty0@gmail.com>
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.

4 participants