Skip to content

Missing disposed cancellation token registration after setting result on Rate Limiting  #76783

@AliKhalili

Description

@AliKhalili

System.Threading.RateLimiting limiter's algorithms are using an internal queue, for queueing async acquire permit requests.
There are some missing calls to disposed of queued requests cancellation token registration after setting their result.
In general, limiters try to dequeue one request from the queue and set the result of the request with a failed or successful lease.
For example, in the replenishments phase(ReplenishInternal), the limiter dequeues one request and, after setting its result, disposes of its cancellation token registration object(nextPendingRequest.CancellationTokenRegistration.Dispose();). also limiter followe same bahvior on Dispose method(next.CancellationTokenRegistration.Dispose();).

private void ReplenishInternal(long nowTicks)
{
    ...
    nextPendingRequest = _options.QueueProcessingOrder == QueueProcessingOrder.OldestFirst
        ? _queue.DequeueHead()
        : _queue.DequeueTail();

    if (!nextPendingRequest.Tcs.TrySetResult(SuccessfulLease)){ ... }
    else { ... }
    nextPendingRequest.CancellationTokenRegistration.Dispose();
}

The limiters should follow the same behavior in the other places, such as when they try to dequeue old requests in order to free some space for pushing new requests on the queue with the newest first processing order policy.

protected override ValueTask<RateLimitLease> AcquireAsyncCore(int permitCount, CancellationToken cancellationToken = default)
{
    ...
    if (_options.QueueProcessingOrder == QueueProcessingOrder.NewestFirst && permitCount <= _options.QueueLimit){
        RequestRegistration oldestRequest = _queue.DequeueHead();
        if (!oldestRequest.Tcs.TrySetResult(FailedLease)){ ... }
        else { ... }
       // Mising dispose
      // oldestRequest.CancellationTokenRegistration.Dispose();
    }
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions