start of request queue

This commit is contained in:
Dylan Dmitri Gray 2019-05-16 16:12:18 -07:00
parent 117dd8cff4
commit 5956609846
10 changed files with 250 additions and 0 deletions

View File

@ -79,6 +79,7 @@
<ProjectReferenceProvider Include="Microsoft.AspNetCore.HttpOverrides" ProjectPath="$(RepoRoot)src\Middleware\HttpOverrides\src\Microsoft.AspNetCore.HttpOverrides.csproj" RefProjectPath="$(RepoRoot)src\Middleware\HttpOverrides\ref\Microsoft.AspNetCore.HttpOverrides.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.HttpsPolicy" ProjectPath="$(RepoRoot)src\Middleware\HttpsPolicy\src\Microsoft.AspNetCore.HttpsPolicy.csproj" RefProjectPath="$(RepoRoot)src\Middleware\HttpsPolicy\ref\Microsoft.AspNetCore.HttpsPolicy.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Localization.Routing" ProjectPath="$(RepoRoot)src\Middleware\Localization.Routing\src\Microsoft.AspNetCore.Localization.Routing.csproj" RefProjectPath="$(RepoRoot)src\Middleware\Localization.Routing\ref\Microsoft.AspNetCore.Localization.Routing.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.RequestQueue" ProjectPath="$(RepositoryRoot)src\Middleware\RequestQueue\src\Microsoft.AspNetCore.RequestQueue.csproj" RefProjectPath="$(RepositoryRoot)src\Middleware\RequestQueue\ref\Microsoft.AspNetCore.RequestQueue.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Localization" ProjectPath="$(RepoRoot)src\Middleware\Localization\src\Microsoft.AspNetCore.Localization.csproj" RefProjectPath="$(RepoRoot)src\Middleware\Localization\ref\Microsoft.AspNetCore.Localization.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.MiddlewareAnalysis" ProjectPath="$(RepoRoot)src\Middleware\MiddlewareAnalysis\src\Microsoft.AspNetCore.MiddlewareAnalysis.csproj" RefProjectPath="$(RepoRoot)src\Middleware\MiddlewareAnalysis\ref\Microsoft.AspNetCore.MiddlewareAnalysis.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.NodeServices" ProjectPath="$(RepoRoot)src\Middleware\NodeServices\src\Microsoft.AspNetCore.NodeServices.csproj" RefProjectPath="$(RepoRoot)src\Middleware\NodeServices\ref\Microsoft.AspNetCore.NodeServices.csproj" />

View File

@ -0,0 +1,14 @@
<!-- This file is automatically generated. -->
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0'">
<Compile Include="Microsoft.AspNetCore.HttpsPolicy.netcoreapp3.0.cs" />
<Reference Include="Microsoft.AspNetCore.Http" />
<Reference Include="Microsoft.AspNetCore.Http.Extensions" />
<Reference Include="Microsoft.Extensions.Configuration.Binder" />
<Reference Include="Microsoft.Extensions.Options" />
<Reference Include="Microsoft.AspNetCore.Hosting.Abstractions" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,51 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNetCore.Builder
{
public static partial class HstsBuilderExtensions
{
public static Microsoft.AspNetCore.Builder.IApplicationBuilder UseHsts(this Microsoft.AspNetCore.Builder.IApplicationBuilder app) { throw null; }
}
public static partial class HstsServicesExtensions
{
public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddHsts(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action<Microsoft.AspNetCore.HttpsPolicy.HstsOptions> configureOptions) { throw null; }
}
public static partial class HttpsPolicyBuilderExtensions
{
public static Microsoft.AspNetCore.Builder.IApplicationBuilder UseHttpsRedirection(this Microsoft.AspNetCore.Builder.IApplicationBuilder app) { throw null; }
}
public static partial class HttpsRedirectionServicesExtensions
{
public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddHttpsRedirection(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action<Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionOptions> configureOptions) { throw null; }
}
}
namespace Microsoft.AspNetCore.HttpsPolicy
{
public partial class HstsMiddleware
{
public HstsMiddleware(Microsoft.AspNetCore.Http.RequestDelegate next, Microsoft.Extensions.Options.IOptions<Microsoft.AspNetCore.HttpsPolicy.HstsOptions> options) { }
public HstsMiddleware(Microsoft.AspNetCore.Http.RequestDelegate next, Microsoft.Extensions.Options.IOptions<Microsoft.AspNetCore.HttpsPolicy.HstsOptions> options, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { }
public System.Threading.Tasks.Task Invoke(Microsoft.AspNetCore.Http.HttpContext context) { throw null; }
}
public partial class HstsOptions
{
public HstsOptions() { }
public System.Collections.Generic.IList<string> ExcludedHosts { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public bool IncludeSubDomains { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public System.TimeSpan MaxAge { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public bool Preload { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
}
public partial class HttpsRedirectionMiddleware
{
public HttpsRedirectionMiddleware(Microsoft.AspNetCore.Http.RequestDelegate next, Microsoft.Extensions.Options.IOptions<Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionOptions> options, Microsoft.Extensions.Configuration.IConfiguration config, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { }
public HttpsRedirectionMiddleware(Microsoft.AspNetCore.Http.RequestDelegate next, Microsoft.Extensions.Options.IOptions<Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionOptions> options, Microsoft.Extensions.Configuration.IConfiguration config, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, Microsoft.AspNetCore.Hosting.Server.Features.IServerAddressesFeature serverAddressesFeature) { }
public System.Threading.Tasks.Task Invoke(Microsoft.AspNetCore.Http.HttpContext context) { throw null; }
}
public partial class HttpsRedirectionOptions
{
public HttpsRedirectionOptions() { }
public int? HttpsPort { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public int RedirectStatusCode { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
}
}

View File

@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.AspNetCore.Server.Kestrel" />
<Reference Include="Microsoft.Extensions.Logging.Console" />
<Reference Include="Microsoft.AspNetCore.HttpsPolicy" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace RequestQueueSample
{
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment environment)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Hello world!");
});
}
// Entry point for the application.
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory()) // for the cert file
.ConfigureLogging(factory =>
{
factory.SetMinimumLevel(LogLevel.Debug);
factory.AddConsole();
})
.UseStartup<Startup>()
.Build();
host.Run();
}
}
}

View File

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>ASP.NET Core middleware for queuing incoming HTTP requests, to avoid threadpool starvation.</Description>
<TargetFramework>netcoreapp3.0</TargetFramework>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<WarningsNotAsErrors>$(WarningsNotAsErrors);CS1591</WarningsNotAsErrors>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.AspNetCore.Http" />
<Reference Include="Microsoft.AspNetCore.Http.Extensions" />
<Reference Include="Microsoft.Extensions.Configuration.Binder" />
<Reference Include="Microsoft.Extensions.Options" />
<Reference Include="Microsoft.AspNetCore.Hosting.Abstractions" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.AspNetCore.RequestQueue
{
internal class SemaphoreWrapper
{
private static SemaphoreSlim semaphore;
public SemaphoreWrapper(int qlength)
{
semaphore = new SemaphoreSlim(qlength);
}
public Task EnterQueue()
{
return semaphore.WaitAsync();
}
public void LeaveQueue()
{
semaphore.Release();
}
public int SpotsLeft
{
get => semaphore.CurrentCount;
}
}
}

View File

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.AspNetCore.RequestQueue" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,56 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Xunit;
using System.Threading;
using System.Threading.Tasks;
using System;
using System.Runtime.CompilerServices;
using Microsoft.AspNetCore.Testing;
namespace Microsoft.AspNetCore.RequestQueue.Tests
{
public class SemaphoreWrapperTests
{
[Fact]
public async Task TestBehavior()
{
var s = new SemaphoreWrapper(1);
Assert.Equal(1, s.SpotsLeft);
await s.EnterQueue();
Assert.Equal(0, s.SpotsLeft);
s.LeaveQueue();
Assert.Equal(1, s.SpotsLeft);
}
[Fact]
public void TestQueueLength()
{
var s = new SemaphoreWrapper(2);
var t1 = s.EnterQueue();
Assert.True(t1.IsCompleted);
var t2 = s.EnterQueue();
Assert.True(t2.IsCompleted);
var t3 = s.EnterQueue();
Assert.False(t3.IsCompleted);
}
[Fact]
public async Task TestWaiting()
{
var s = new SemaphoreWrapper(1);
await s.EnterQueue();
var waitingTask = s.EnterQueue();
Assert.False(waitingTask.IsCompleted);
s.LeaveQueue();
await waitingTask.TimeoutAfter(TimeSpan.FromSeconds(1));
}
}
}

3
src/Middleware/build.cmd Normal file
View File

@ -0,0 +1,3 @@
@ECHO OFF
SET RepoRoot=%~dp0..\..
%RepoRoot%\build.cmd -projects %~dp0\**\*.*proj %*