public async Task Invoke_NoThrottle_DispatchesDirectly() { bool nextInvoked = false; RequestDelegate next = (ctxt) => { nextInvoked = true; ctxt.Response.StatusCode = (int)HttpStatusCode.Accepted; return(Task.CompletedTask); }; var options = new HttpOptions(); var middleware = new HttpThrottleMiddleware(next, _loggerFactory, TimeSpan.FromSeconds(1)); var httpContext = new DefaultHttpContext(); await middleware.Invoke(httpContext, new OptionsWrapper <HttpOptions>(_httpOptions), _requestQueue, _performanceManager.Object, _metricsLogger.Object); Assert.True(nextInvoked); Assert.Equal(HttpStatusCode.Accepted, (HttpStatusCode)httpContext.Response.StatusCode); }
public async Task Invoke_MaxParallelism_RequestsAreThrottled() { int maxParallelism = 3; _httpOptions = new HttpOptions { MaxConcurrentRequests = maxParallelism }; _requestQueue = new HttpRequestQueue(new OptionsWrapper <HttpOptions>(_httpOptions)); int count = 0; RequestDelegate next = async(ctxt) => { if (Interlocked.Increment(ref count) > maxParallelism) { throw new Exception($"Max parallelism of {maxParallelism} exceeded. Current parallelism: {count}"); } await Task.Delay(100); Interlocked.Decrement(ref count); ctxt.Response.StatusCode = (int)HttpStatusCode.Accepted; }; var middleware = new HttpThrottleMiddleware(next, _loggerFactory, TimeSpan.FromSeconds(1)); // expect all requests to succeed var tasks = new List <Task>(); var httpContexts = new List <HttpContext>(); for (int i = 0; i < 20; i++) { var httpContext = new DefaultHttpContext(); httpContexts.Add(httpContext); tasks.Add(middleware.Invoke(httpContext, new OptionsWrapper <HttpOptions>(_httpOptions), _requestQueue, _performanceManager.Object, _metricsLogger.Object)); } await Task.WhenAll(tasks); Assert.True(httpContexts.All(p => (HttpStatusCode)p.Response.StatusCode == HttpStatusCode.Accepted)); }
public async Task Invoke_HostIsOverloaded_RequestsAreRejected() { _httpOptions = new HttpOptions { DynamicThrottlesEnabled = true }; _requestQueue = new HttpRequestQueue(new OptionsWrapper <HttpOptions>(_httpOptions)); bool isOverloaded = false; _performanceManager.Setup(p => p.PerformanceCountersExceeded(It.IsAny <Collection <string> >(), It.IsAny <ILogger>())).Returns(() => isOverloaded); RequestDelegate next = async(ctxt) => { await Task.Delay(100); ctxt.Response.StatusCode = (int)HttpStatusCode.Accepted; }; var middleware = new HttpThrottleMiddleware(next, _loggerFactory, TimeSpan.FromMilliseconds(50)); var tasks = new List <Task>(); var httpContexts = new List <HttpContext>(); for (int i = 0; i < 10; i++) { if (i == 7) { isOverloaded = true; } var httpContext = new DefaultHttpContext(); httpContexts.Add(httpContext); await middleware.Invoke(httpContext, new OptionsWrapper <HttpOptions>(_httpOptions), _requestQueue, _performanceManager.Object, _metricsLogger.Object); } await Task.WhenAll(tasks); Assert.Equal(7, httpContexts.Count(p => (HttpStatusCode)p.Response.StatusCode == HttpStatusCode.Accepted)); Assert.Equal(3, httpContexts.Count(p => (HttpStatusCode)p.Response.StatusCode == HttpStatusCode.TooManyRequests)); }
public async Task Invoke_UnderLoad_RequestsAreRejected() { _httpOptions.DynamicThrottlesEnabled = true; bool highLoad = false; int highLoadQueryCount = 0; _performanceManager.Setup(p => p.PerformanceCountersExceeded(It.IsAny <Collection <string> >(), It.IsAny <ILogger>())) .Callback <Collection <string>, ILogger>((exceededCounters, tw) => { if (highLoad) { exceededCounters.Add("Threads"); exceededCounters.Add("Processes"); } }).Returns(() => { highLoadQueryCount++; return(highLoad); }); // issue some requests while not under high load for (int i = 0; i < 3; i++) { var httpContext = new DefaultHttpContext(); await _middleware.Invoke(httpContext, new OptionsWrapper <HttpOptions>(_httpOptions), _requestQueue, _performanceManager.Object, _metricsLogger.Object); Assert.Equal(HttpStatusCode.Accepted, (HttpStatusCode)httpContext.Response.StatusCode); await Task.Delay(100); } Assert.Equal(1, highLoadQueryCount); Assert.Equal(0, _throttleMetricCount); // signal high load and verify requests are rejected await Task.Delay(1000); highLoad = true; for (int i = 0; i < 3; i++) { var httpContext = new DefaultHttpContext(); await _middleware.Invoke(httpContext, new OptionsWrapper <HttpOptions>(_httpOptions), _requestQueue, _performanceManager.Object, _metricsLogger.Object); httpContext.Response.Headers.TryGetValue(ScriptConstants.AntaresScaleOutHeaderName, out StringValues values); string scaleOutHeader = values.Single(); Assert.Equal("1", scaleOutHeader); Assert.Equal(HttpStatusCode.TooManyRequests, (HttpStatusCode)httpContext.Response.StatusCode); await Task.Delay(100); } Assert.Equal(2, highLoadQueryCount); Assert.Equal(3, _throttleMetricCount); var log = _loggerProvider.GetAllLogMessages().Last(); Assert.Equal("Thresholds for the following counters have been exceeded: [Threads, Processes]", log.FormattedMessage); await Task.Delay(1000); highLoad = false; for (int i = 0; i < 3; i++) { var httpContext = new DefaultHttpContext(); await _middleware.Invoke(httpContext, new OptionsWrapper <HttpOptions>(_httpOptions), _requestQueue, _performanceManager.Object, _metricsLogger.Object); Assert.Equal(HttpStatusCode.Accepted, (HttpStatusCode)httpContext.Response.StatusCode); await Task.Delay(100); } Assert.Equal(3, highLoadQueryCount); Assert.Equal(3, _throttleMetricCount); }