Improve performance for QueuePolicy in ConcurrencyLimiter (#13947)
This commit is contained in:
parent
ab5b5a4ab5
commit
61179f3da2
|
|
@ -10,31 +10,35 @@ namespace Microsoft.AspNetCore.ConcurrencyLimiter
|
||||||
{
|
{
|
||||||
internal class QueuePolicy : IQueuePolicy, IDisposable
|
internal class QueuePolicy : IQueuePolicy, IDisposable
|
||||||
{
|
{
|
||||||
private readonly int _maxConcurrentRequests;
|
private readonly int _maxTotalRequest;
|
||||||
private readonly int _requestQueueLimit;
|
|
||||||
private readonly SemaphoreSlim _serverSemaphore;
|
private readonly SemaphoreSlim _serverSemaphore;
|
||||||
|
|
||||||
private object _totalRequestsLock = new object();
|
private object _totalRequestsLock = new object();
|
||||||
|
|
||||||
public int TotalRequests { get; private set; }
|
public int TotalRequests { get; private set; }
|
||||||
|
|
||||||
public QueuePolicy(IOptions<QueuePolicyOptions> options)
|
public QueuePolicy(IOptions<QueuePolicyOptions> options)
|
||||||
{
|
{
|
||||||
_maxConcurrentRequests = options.Value.MaxConcurrentRequests;
|
var queuePolicyOptions = options.Value;
|
||||||
if (_maxConcurrentRequests <= 0)
|
|
||||||
|
var maxConcurrentRequests = queuePolicyOptions.MaxConcurrentRequests;
|
||||||
|
if (maxConcurrentRequests <= 0)
|
||||||
{
|
{
|
||||||
throw new ArgumentException(nameof(_maxConcurrentRequests), "MaxConcurrentRequests must be a positive integer.");
|
throw new ArgumentException(nameof(maxConcurrentRequests), "MaxConcurrentRequests must be a positive integer.");
|
||||||
}
|
}
|
||||||
|
|
||||||
_requestQueueLimit = options.Value.RequestQueueLimit;
|
var requestQueueLimit = queuePolicyOptions.RequestQueueLimit;
|
||||||
if (_requestQueueLimit < 0)
|
if (requestQueueLimit < 0)
|
||||||
{
|
{
|
||||||
throw new ArgumentException(nameof(_requestQueueLimit), "The RequestQueueLimit cannot be a negative number.");
|
throw new ArgumentException(nameof(requestQueueLimit), "The RequestQueueLimit cannot be a negative number.");
|
||||||
}
|
}
|
||||||
|
|
||||||
_serverSemaphore = new SemaphoreSlim(_maxConcurrentRequests);
|
_serverSemaphore = new SemaphoreSlim(maxConcurrentRequests);
|
||||||
|
|
||||||
|
_maxTotalRequest = maxConcurrentRequests + requestQueueLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async ValueTask<bool> TryEnterAsync()
|
public ValueTask<bool> TryEnterAsync()
|
||||||
{
|
{
|
||||||
// a return value of 'false' indicates that the request is rejected
|
// a return value of 'false' indicates that the request is rejected
|
||||||
// a return value of 'true' indicates that the request may proceed
|
// a return value of 'true' indicates that the request may proceed
|
||||||
|
|
@ -42,17 +46,21 @@ namespace Microsoft.AspNetCore.ConcurrencyLimiter
|
||||||
|
|
||||||
lock (_totalRequestsLock)
|
lock (_totalRequestsLock)
|
||||||
{
|
{
|
||||||
if (TotalRequests >= _requestQueueLimit + _maxConcurrentRequests)
|
if (TotalRequests >= _maxTotalRequest)
|
||||||
{
|
{
|
||||||
return false;
|
return new ValueTask<bool>(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TotalRequests++;
|
TotalRequests++;
|
||||||
}
|
}
|
||||||
|
|
||||||
await _serverSemaphore.WaitAsync();
|
Task task = _serverSemaphore.WaitAsync();
|
||||||
|
if (task.IsCompletedSuccessfully)
|
||||||
|
{
|
||||||
|
return new ValueTask<bool>(true);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return SemaphoreAwaited(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnExit()
|
public void OnExit()
|
||||||
|
|
@ -69,5 +77,12 @@ namespace Microsoft.AspNetCore.ConcurrencyLimiter
|
||||||
{
|
{
|
||||||
_serverSemaphore.Dispose();
|
_serverSemaphore.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async ValueTask<bool> SemaphoreAwaited(Task task)
|
||||||
|
{
|
||||||
|
await task;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,6 @@ namespace Microsoft.AspNetCore.ConcurrencyLimiter
|
||||||
|
|
||||||
private readonly object _bufferLock = new Object();
|
private readonly object _bufferLock = new Object();
|
||||||
|
|
||||||
private readonly static ValueTask<bool> _trueTask = new ValueTask<bool>(true);
|
|
||||||
|
|
||||||
private int _freeServerSpots;
|
private int _freeServerSpots;
|
||||||
|
|
||||||
public StackPolicy(IOptions<QueuePolicyOptions> options)
|
public StackPolicy(IOptions<QueuePolicyOptions> options)
|
||||||
|
|
@ -40,7 +38,7 @@ namespace Microsoft.AspNetCore.ConcurrencyLimiter
|
||||||
if (_freeServerSpots > 0)
|
if (_freeServerSpots > 0)
|
||||||
{
|
{
|
||||||
_freeServerSpots--;
|
_freeServerSpots--;
|
||||||
return _trueTask;
|
return new ValueTask<bool>(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if queue is full, cancel oldest request
|
// if queue is full, cancel oldest request
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue