Skip to content

Fix NoopLimiter disposal in DefaultPartitionedRateLimiter Heartbeat#127582

Open
Copilot wants to merge 17 commits into
mainfrom
copilot/fix-noop-limiter-disposal
Open

Fix NoopLimiter disposal in DefaultPartitionedRateLimiter Heartbeat#127582
Copilot wants to merge 17 commits into
mainfrom
copilot/fix-noop-limiter-disposal

Conversation

Copilot AI commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

Fixes DefaultPartitionedRateLimiter so that NoopLimiter partitions are evicted and disposed by the Heartbeat timer, which previously never happened because NoopLimiter.IdleDuration always returns null.

Changes Made

  • Introduced a LimiterEntry wrapper that tracks a LastAccessTimestamp (updated on each Acquire/WaitAsync call) alongside the RateLimiter instance.
  • Added GetIdleDuration(LimiterEntry) helper that falls back to the elapsed time since last access for NoopLimiter (whose IdleDuration is always null), and returns null for all other limiter types that return null (preserving the existing "do not evict" contract).
  • Updated the Heartbeat eviction check to use the is TimeSpan idleDuration && idleDuration > s_idleTimeLimit pattern (with ?? TimeSpan.Zero for the under-lock re-check), correctly handling the nullable TimeSpan? return — null skips eviction, matching the original pattern.
  • Used Volatile.Read/Volatile.Write for atomic 64-bit timestamp access on 32-bit platforms.
  • Added a RateLimiterHelper.GetElapsedTime(long) overload to avoid .GetValueOrDefault() at call sites.
  • Added tests covering NoopLimiter eviction via Heartbeat and verifying that non-NoopLimiter partitions with IdleDuration == null are not evicted while active.

Copilot AI requested review from Copilot and removed request for Copilot April 29, 2026 20:47
Copilot AI linked an issue Apr 29, 2026 that may be closed by this pull request
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @VSadov
See info in area-owners.md if you want to be subscribed.

Copilot AI requested review from Copilot and removed request for Copilot April 29, 2026 21:12
Copilot AI changed the title [WIP] Fix DefaultPartitionedRateLimiter to dispose NoopLimiter Evict idle partitions whose IdleDuration is always null Apr 29, 2026
Copilot AI requested a review from VSadov April 29, 2026 21:18

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

Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.

Comment on lines +624 to +630
var limiterTypeDef = Type.GetType("System.Threading.RateLimiting.DefaultPartitionedRateLimiter`2, System.Threading.RateLimiting");
Assert.NotNull(limiterTypeDef);
var limiterType = limiterTypeDef.MakeGenericType(typeof(TResource), typeof(TKey));

var limitersField = limiterType.GetField("_limiters", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
Assert.NotNull(limitersField);
var limitersDict = (System.Collections.IDictionary)limitersField.GetValue(limiter);
Comment thread src/libraries/System.Threading.RateLimiting/tests/PartitionedRateLimiterTests.cs Outdated
Comment thread src/libraries/System.Threading.RateLimiting/tests/PartitionedRateLimiterTests.cs Outdated
Comment thread src/libraries/System.Threading.RateLimiting/tests/PartitionedRateLimiterTests.cs Outdated

private static object GetLazyLimiterEntry<TResource, TKey>(PartitionedRateLimiter<TResource> limiter, TKey key)
{
// Use Type.GetType so that trimming can see what type we're reflecting on, but assert it's the one we got
Comment on lines +325 to +327
public RateLimiter Limiter { get; }
public long LastAccessTimestamp;
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

AI-generated.

Addressed in 478398c.

Copilot AI and others added 2 commits June 14, 2026 18:18
Co-authored-by: VSadov <8218165+VSadov@users.noreply.github.com>
Co-authored-by: VSadov <8218165+VSadov@users.noreply.github.com>
…e in GetLazyLimiterEntry

Co-authored-by: VSadov <8218165+VSadov@users.noreply.github.com>
Copilot AI requested review from Copilot and removed request for Copilot June 14, 2026 18:30
Copilot AI changed the title Evict idle partitions whose IdleDuration is always null Add type-instance assertion before reflection GetValue in rate limiter test helper Jun 14, 2026
Co-authored-by: VSadov <8218165+VSadov@users.noreply.github.com>
Copilot AI requested review from Copilot and removed request for Copilot June 14, 2026 18:31
Co-authored-by: VSadov <8218165+VSadov@users.noreply.github.com>
Copilot AI changed the title Add type-instance assertion before reflection GetValue in rate limiter test helper Fix NoopLimiter partition eviction in DefaultPartitionedRateLimiter Jun 14, 2026
Copilot AI requested review from Copilot and removed request for Copilot June 14, 2026 18:31
Co-authored-by: VSadov <8218165+VSadov@users.noreply.github.com>
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.

DefaultPartitionedRateLimiter never disposes NoopLimiter

4 participants