[英]Limit concurrency per API endpoint
How can I limit concurrency per API endpoint in .net core.如何限制 .net 核心中每个 API 端点的并发性。 I need one endpoint to be limited to single request in my microservice.
我需要一个端点来限制我的微服务中的单个请求。
Though I am curious about the actual details supporting your particular use case for a singleton web service.尽管我对支持您的单例 Web 服务特定用例的实际细节感到好奇。 I will answer your question.
我会回答你的问题。
The most elegant solution that comes to mind is the use of custom middle ware: Write custom ASP.NET Core middleware想到的最优雅的解决方案是使用自定义中间件: 编写自定义 ASP.NET Core 中间件
The code for it might be something like this:它的代码可能是这样的:
// Example middleware
using System;
using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Caching.Memory;
namespace YourNamespaceHere
{
public class MySingleRequestLimitingMiddleware
{
private readonly RequestDelegate _next;
private readonly IMemoryCache _cache;
private readonly string FlagCacheKey = "RequestAvailability";
private readonly string _statusLocked = "locked";
private readonly string _statusAvailable = "available";
public MySingleRequestLimitingMiddleware(RequestDelegate next,
IMemoryCache cache)
{
_next = next;
_cache = cache;
}
public async Task Invoke(HttpContext httpContext)
{
string cacheEntry;
// Set cache options.
var cacheEntryOptions = new MemoryCacheEntryOptions()
// Keep in cache for 2 minutes.
.SetAbsoluteExpiration(DateTimeOffset.Now.AddMinutes(2));
// Look for the cache key.
if (!_cache.TryGetValue(FlagCacheKey, out cacheEntry))
{
// Key not in cache, so set lock.
cacheEntry = _statusAvailable;
// Save data in cache.
_cache.Set(FlagCacheKey, cacheEntry, cacheEntryOptions);
}
if (cacheEntry.Equals(_statusLocked, StringComparison.OrdinalIgnoreCase))
{
httpContext.Response.StatusCode = (int)HttpStatusCode.TooManyRequests;
httpContext.Response.ContentType = "text/plain";
await httpContext.Response.WriteAsync("Maximum API calls admitted: 1.");
return;
}
/* ***BEWARE: You are entering the request the next line
* will lock up the call until this flag is changed.
* You must set the flag in your controller or somewhere else every single
* request no fail or your call will be left in an unusable state.
* The only thing that fixes the state if you fail to change state
* is restarting the service or waiting 2 minutes. */
_cache.Set(FlagCacheKey, _statusLocked, cacheEntryOptions);
await _next.Invoke(httpContext);
}
}
}
// In your Startup.cs
namespace YourNamespaceHere
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMemoryCache(); // Add this line to yours somewhere
}
public void Configure(IApplicationBuilder app)
{
// Put it at very top because you don't need to run anything
// else if the limit of 1 request has already been reached.
app.UseWhen(context => context.Request.Path.StartsWithSegments("/somepathtoyourcallhere"), appBuilder =>
{
appBuilder.UseMySingleRequestLimitingMiddleware();
});
// The rest of your code
}
}
}
// Example Controller
// In the controller containing your singleton request call
// ***NOTE you MUST set the flag even if there is an error!!!
public class SomeController : Controller
{
private IMemoryCache _cache;
public SomeController(IMemoryCache memoryCache)
{
_cache = memoryCache;
}
[HttpPost]
public IActionResult YourSingleServiceRequestActionNameHere(SomeMode model)
{
// Some code here...
_cache.Set(FlagCacheKey, "available", new MemoryCacheEntryOptions()
.SetAbsoluteExpiration(DateTimeOffset.Now.AddMinutes(2)));
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
// Just in case you didn't set that flag already lets make sure.
_cache.Set(FlagCacheKey, "available", new MemoryCacheEntryOptions()
.SetAbsoluteExpiration(DateTimeOffset.Now.AddMinutes(2)));
}
base.Dispose(disposing);
}
}
You can also consider the use of IP or Client limit rating middleware such as: AspNetCoreRateLimit也可以考虑使用IP或者Client limit rating中间件比如: AspNetCoreRateLimit
Since we do not know when the request will complete we will just set the cache expiration for 2 minutes so the service becomes unusable for no longer than 2 minutes if the flag fails to be updated in your code.由于我们不知道请求何时完成,因此我们将缓存过期时间设置为 2 分钟,因此如果您的代码中的标志无法更新,服务将在不超过 2 分钟的时间内无法使用。 Does your call take 2 minutes to complete?
您的通话是否需要 2 分钟才能完成? If so then a web request may time out before the request even completes.
如果是这样,那么 Web 请求可能会在请求完成之前超时。
If it does take more than 2 minutes to complete consider if a web service call is the proper solution.如果完成时间超过 2 分钟,请考虑 Web 服务调用是否是正确的解决方案。
Hope that helps.希望有帮助。
Happy coding!!!快乐编码!!!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.