Remove request limit throttle. Move to middleware later.
This commit is contained in:
parent
27d834ae6a
commit
fd510db13c
|
|
@ -1,89 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics.Contracts;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Server.WebListener
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// AwaitableThrottle is an awaitable object that acts like a semaphore. The object would wait if more than maxConcurrent number of clients waits on it.
|
|
||||||
/// </summary>
|
|
||||||
internal class AwaitableThrottle
|
|
||||||
{
|
|
||||||
private static readonly TaskAwaiter<bool> CompletedAwaiter = Task.FromResult(true).GetAwaiter();
|
|
||||||
|
|
||||||
private int _maxConcurrent;
|
|
||||||
private readonly object _thislock;
|
|
||||||
private readonly Queue<TaskCompletionSource<bool>> _awaiters;
|
|
||||||
|
|
||||||
private int _count;
|
|
||||||
|
|
||||||
// <param name="maxConcurrent">Maximum number of clients that can wait on this object at the same time.</param>
|
|
||||||
public AwaitableThrottle(int maxConcurrent)
|
|
||||||
{
|
|
||||||
_thislock = new object();
|
|
||||||
_awaiters = new Queue<TaskCompletionSource<bool>>();
|
|
||||||
_maxConcurrent = maxConcurrent;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int MaxConcurrent
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _maxConcurrent;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
Contract.Assert(_maxConcurrent >= 0,
|
|
||||||
"Behavior of this class is undefined for negative value");
|
|
||||||
// Note:
|
|
||||||
// 1. This setter is non-thread safe. We assumed it doesnt need to be for simplicity sake.
|
|
||||||
// 2. Behavior of this class is not well defined if a negative value is passed in. If it
|
|
||||||
// is awaited before any Release() is called, the subsequent Relese() would eagerly
|
|
||||||
// unblock awaiting thread instead of waiting for _count to reach the negative value specified.
|
|
||||||
_maxConcurrent = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public TaskAwaiter<bool> GetAwaiter()
|
|
||||||
{
|
|
||||||
TaskCompletionSource<bool> awaiter;
|
|
||||||
|
|
||||||
lock (_thislock)
|
|
||||||
{
|
|
||||||
if (_count < _maxConcurrent)
|
|
||||||
{
|
|
||||||
_count++;
|
|
||||||
return CompletedAwaiter;
|
|
||||||
}
|
|
||||||
|
|
||||||
awaiter = new TaskCompletionSource<bool>();
|
|
||||||
_awaiters.Enqueue(awaiter);
|
|
||||||
}
|
|
||||||
|
|
||||||
return awaiter.Task.GetAwaiter();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Release()
|
|
||||||
{
|
|
||||||
TaskCompletionSource<bool> completion = null;
|
|
||||||
|
|
||||||
lock (_thislock)
|
|
||||||
{
|
|
||||||
if (_awaiters.Count > 0)
|
|
||||||
{
|
|
||||||
completion = _awaiters.Dequeue();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_count--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (completion != null)
|
|
||||||
{
|
|
||||||
completion.SetResult(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -18,13 +18,11 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
{
|
{
|
||||||
internal struct PumpLimits
|
internal struct PumpLimits
|
||||||
{
|
{
|
||||||
internal PumpLimits(int maxAccepts, int maxRequests)
|
internal PumpLimits(int maxAccepts)
|
||||||
{
|
{
|
||||||
MaxOutstandingAccepts = maxAccepts;
|
MaxOutstandingAccepts = maxAccepts;
|
||||||
MaxOutstandingRequests = maxRequests;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal readonly int MaxOutstandingAccepts;
|
internal readonly int MaxOutstandingAccepts;
|
||||||
internal readonly int MaxOutstandingRequests;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
public class WebListenerWrapper : IDisposable
|
public class WebListenerWrapper : IDisposable
|
||||||
{
|
{
|
||||||
private static readonly int DefaultMaxAccepts = 5 * Environment.ProcessorCount;
|
private static readonly int DefaultMaxAccepts = 5 * Environment.ProcessorCount;
|
||||||
private static readonly int DefaultMaxRequests = Int32.MaxValue;
|
|
||||||
|
|
||||||
private OwinWebListener _listener;
|
private OwinWebListener _listener;
|
||||||
private AppFunc _appFunc;
|
private AppFunc _appFunc;
|
||||||
|
|
@ -24,7 +23,6 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
private PumpLimits _pumpLimits;
|
private PumpLimits _pumpLimits;
|
||||||
private int _acceptorCounts;
|
private int _acceptorCounts;
|
||||||
private Action<object> _processRequest;
|
private Action<object> _processRequest;
|
||||||
private readonly AwaitableThrottle _requestProcessingThrottle;
|
|
||||||
|
|
||||||
// TODO: private IDictionary<string, object> _capabilities;
|
// TODO: private IDictionary<string, object> _capabilities;
|
||||||
|
|
||||||
|
|
@ -34,8 +32,7 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
_listener = listener;
|
_listener = listener;
|
||||||
|
|
||||||
_processRequest = new Action<object>(ProcessRequestAsync);
|
_processRequest = new Action<object>(ProcessRequestAsync);
|
||||||
_pumpLimits = new PumpLimits(DefaultMaxAccepts, DefaultMaxRequests);
|
_pumpLimits = new PumpLimits(DefaultMaxAccepts);
|
||||||
_requestProcessingThrottle = new AwaitableThrottle(DefaultMaxRequests);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Start(AppFunc app, IList<IDictionary<string, object>> addresses, LoggerFactoryFunc loggerFactory)
|
internal void Start(AppFunc app, IList<IDictionary<string, object>> addresses, LoggerFactoryFunc loggerFactory)
|
||||||
|
|
@ -72,10 +69,9 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
/// This controls how many requests the server attempts to process concurrently.
|
/// This controls how many requests the server attempts to process concurrently.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="maxAccepts">The maximum number of pending accepts.</param>
|
/// <param name="maxAccepts">The maximum number of pending accepts.</param>
|
||||||
/// <param name="maxRequests">The maximum number of outstanding requests.</param>
|
public void SetRequestProcessingLimits(int maxAccepts)
|
||||||
public void SetRequestProcessingLimits(int maxAccepts, int maxRequests)
|
|
||||||
{
|
{
|
||||||
_pumpLimits = new PumpLimits(maxAccepts, maxRequests);
|
_pumpLimits = new PumpLimits(maxAccepts);
|
||||||
|
|
||||||
if (_listener.IsListening)
|
if (_listener.IsListening)
|
||||||
{
|
{
|
||||||
|
|
@ -85,8 +81,6 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
|
|
||||||
private void ActivateRequestProcessingLimits()
|
private void ActivateRequestProcessingLimits()
|
||||||
{
|
{
|
||||||
_requestProcessingThrottle.MaxConcurrent = _pumpLimits.MaxOutstandingRequests;
|
|
||||||
|
|
||||||
for (int i = _acceptorCounts; i < _pumpLimits.MaxOutstandingAccepts; i++)
|
for (int i = _acceptorCounts; i < _pumpLimits.MaxOutstandingAccepts; i++)
|
||||||
{
|
{
|
||||||
ProcessRequestsWorker();
|
ProcessRequestsWorker();
|
||||||
|
|
@ -97,14 +91,11 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
/// Gets the request processing limits.
|
/// Gets the request processing limits.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="maxAccepts">The maximum number of pending accepts.</param>
|
/// <param name="maxAccepts">The maximum number of pending accepts.</param>
|
||||||
/// <param name="maxRequests">The maximum number of outstanding requests.</param>
|
|
||||||
[SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "0#", Justification = "By design")]
|
[SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "0#", Justification = "By design")]
|
||||||
[SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "1#", Justification = "By design")]
|
public void GetRequestProcessingLimits(out int maxAccepts)
|
||||||
public void GetRequestProcessingLimits(out int maxAccepts, out int maxRequests)
|
|
||||||
{
|
{
|
||||||
PumpLimits limits = _pumpLimits;
|
PumpLimits limits = _pumpLimits;
|
||||||
maxAccepts = limits.MaxOutstandingAccepts;
|
maxAccepts = limits.MaxOutstandingAccepts;
|
||||||
maxRequests = limits.MaxOutstandingRequests;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The message pump.
|
// The message pump.
|
||||||
|
|
@ -116,8 +107,6 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
int workerIndex = Interlocked.Increment(ref _acceptorCounts);
|
int workerIndex = Interlocked.Increment(ref _acceptorCounts);
|
||||||
while (_listener.IsListening && workerIndex <= _pumpLimits.MaxOutstandingAccepts)
|
while (_listener.IsListening && workerIndex <= _pumpLimits.MaxOutstandingAccepts)
|
||||||
{
|
{
|
||||||
await _requestProcessingThrottle;
|
|
||||||
|
|
||||||
// Receive a request
|
// Receive a request
|
||||||
RequestContext requestContext;
|
RequestContext requestContext;
|
||||||
try
|
try
|
||||||
|
|
@ -139,7 +128,6 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
// Request processing failed to be queued in threadpool
|
// Request processing failed to be queued in threadpool
|
||||||
// Log the error message, release throttle and move on
|
// Log the error message, release throttle and move on
|
||||||
LogHelper.LogException(_logger, "ProcessRequestAsync", ex);
|
LogHelper.LogException(_logger, "ProcessRequestAsync", ex);
|
||||||
_requestProcessingThrottle.Release();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Interlocked.Decrement(ref _acceptorCounts);
|
Interlocked.Decrement(ref _acceptorCounts);
|
||||||
|
|
@ -152,7 +140,6 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// TODO: Make disconnect registration lazy
|
|
||||||
FeatureContext featureContext = new FeatureContext(requestContext);
|
FeatureContext featureContext = new FeatureContext(requestContext);
|
||||||
await _appFunc(featureContext.Features).SupressContext();
|
await _appFunc(featureContext.Features).SupressContext();
|
||||||
await requestContext.ProcessResponseAsync().SupressContext();
|
await requestContext.ProcessResponseAsync().SupressContext();
|
||||||
|
|
@ -178,10 +165,6 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
requestContext.Abort();
|
requestContext.Abort();
|
||||||
requestContext.Dispose();
|
requestContext.Dispose();
|
||||||
}
|
}
|
||||||
finally
|
|
||||||
{
|
|
||||||
_requestProcessingThrottle.Release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue