Request timeouts middleware
See original GitHub issueBackground and Motivation
A common customer request is to be able to apply timeouts to their requests. AspNetCore servers don’t do this by default since request times vary widely by scenario and we don’t have good ways to predict that. E.g. WebSockets, static files, expensive APIs, etc…
- https://github.com/dotnet/aspnetcore/issues/23160 - Out-of-proc had request timeouts.
- https://github.com/dotnet/aspnetcore/issues/10079
- https://github.com/aspnet/KestrelHttpServer/pull/485#discussion_r55264843
- https://github.com/aspnet/KestrelHttpServer/issues/611
To provide more control we can provide timeouts via middleware that are configured per-endpoint, as well as a global timeout if desired. These timeouts would link to the RequestAborted CancellationToken and be entirely cooperative. E.g. we won’t call Abort when the timeout fires. It’s up to the application logic to consume RequestAborted and decide how to handle the cancellation.
Proposed API
Project/Assembly: Microsoft.AspNetCore.Http
namespace Microsoft.Extensions.DependencyInjection;
+ public static class RequestTimeoutsIServiceCollectionExtensions
+ {
+ public static IServiceCollection AddRequestTimeouts(this IServiceCollection services) { }
+ public static IServiceCollection AddRequestTimeouts(this IServiceCollection services, Action<RequestTimeoutOptions> configure) { }
+ // We need to consider how these policies would integrate with IConfiguration, but that may be substantially different from this API.
+ // public static IServiceCollection AddRequestTimeouts(this IServiceCollection services, IConfigurationSection section) { }
+ }
namespace Microsoft.AspNetCore.Builder;
+ public static class RequestTimeoutsIApplicationBuilderExtensions
+ {
+ public static IApplicationBuilder UseRequestTimeouts(this IApplicationBuilder builder) { }
+ }
+ public static class RequestTimeoutsIEndpointConventionBuilderExtensions
+ {
+ public static IEndpointConventionBuilder WithRequestTimeout(this IEndpointConventionBuilder builder, TimeSpan timeout) { }
+ public static IEndpointConventionBuilder WithRequestTimeout(this IEndpointConventionBuilder builder, string policyName) { }
+ public static IEndpointConventionBuilder WithRequestTimeout(this IEndpointConventionBuilder builder, RequestTimeoutPolicy policy) { }
+ public static IEndpointConventionBuilder DisableRequestTimeout(this IEndpointConventionBuilder builder) { }
+ }
+ namespace Microsoft.AspNetCore.Http.Timeouts;
+ public class RequestTimeoutOptions
+ {
+ // Applied to any request without a policy set. No value by default.
+ public TimeSpan? DefaultTimeout { get; set; }
+ public RequestTimeoutOptions AddPolicy(string policyName, TimeSpan timeout) { }
+ public RequestTimeoutOptions AddPolicy(string policyName, RequestTimeoutPolicy policy) { }
+ public bool TryGetPolicy(string policyName, out RequestTimeoutPolicy policy) { }
+ public void RemovePolicy(string policyName) { }
+ }
+ public class RequestTimeoutPolicy
+ {
+ public TimeSpan? Timeout { get; }
+ public RequestTimeoutPolicy(TimeSpan? timeout) { }
+ }
+ // Overrides the global timeout, if any.
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
+ public sealed class RequestTimeoutAttribute : Attribute
+ {
+ public TimeSpan? Timeout { get; }
+ public string? PolicyName { get; }
+ public RequestTimeoutAttribute(int seconds) { }
+ public RequestTimeoutAttribute(string policyName) { }
+ }
+ // Disables all timeouts, even the global one.
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
+ public sealed class DisableRequestTimeoutAttribute : Attribute
+ {
+ public DisableRequestTimeoutAttribute() { }
+ }
Usage Examples
services.AddRequestTimeout(options =>
{
options.DefaultTimeout = TimeSpan.FromSeconds(10);
options.DefaultTimeoutLocator = context => TimeSpan.Parse(context.Request.Query["delay"]);
options.AddPolicy("MyTimeoutPolicy", TimeSpan.FromSeconds(1));
options.AddPolicy("DynamicPolicy", new RequestTimeoutPolicy(context => TimeSpan.Parse(context.Request.Query["timeout"])));
});
...
app.UseRequestTimeouts();
...
app.UseEndpoints(endpoints => {
endpoints
.MapGet("/", (context) => { ... })
.WithRequestTimeout(TimeSpan.FromSeconds(1));
app.UseEndpoints(endpoints => {
endpoints
.MapGet("/", (context) => { ... })
.WithRequestTimeout("MyTimeoutPolicy");
...
[RequestTimeout(seconds: 1)]
public ActionResult<TValue> GetHello()
{
return "Hello";
}
[RequestTimeout("MyTimeoutPolicy")]
public ActionResult<TValue> GetHello()
{
return "Hello";
}
[DisableRequestTimeout]
public ActionResult<TValue> ImVerySlow()
{
Thread.Sleep(TimeSpan.FromHours(1);
return "Hello";
}
Alternative Designs
Risks
- We need to ensure this system is flexible enough to cover a wide variety of scenarios, while being easy enough for people to not mis-configure.
- What about components that don’t use endpoints?
- What if the middleware is placed in the wrong location?
Issue Analytics
- State:
- Created 9 months ago
- Reactions:1
- Comments:32 (32 by maintainers)
Top Results From Across the Web
Express timeout middleware
Returns middleware that times out in time milliseconds. time can also be a string accepted by the ms module. On timeout, req will...
Read more >ASP.NET Core 5 - Timeout middleware outputting phantom ...
Delay on the corresponding controller. So I opened up fiddler and (to my surprise) several requests are returning in 1.3-1.7 seconds WITH A...
Read more >Timeout - Echo, LabStack
Timeout middleware is used to timeout at a long running operation within a predefined period. Usage. e.Use(middleware.Timeout ...
Read more >timeout-middleware - npm Package Health Analysis
Express middleware for handling timeouts for slow requests. Visit Snyk Advisor to see a full health score report for timeout-middleware, including popularity, ...
Read more >ASP.NET Core Request Timeout IIS In-Process Mode
ASP.NET Core request timeout, when hosted in IIS in-process mode, doesn't work the way you think it does. Learn one way to make...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
How about also adding
DisableRequestTimeout
onIEndpointConventionBuilder
?https://github.com/dotnet/aspnetcore/issues/43642