public async Task Invoke(HttpContext context) { CapacityCheckResult checkResult = _capacityGuard.CheckCapacity(context.RequestAborted); if (!checkResult.ExecutionAllowed) { EnqueueStatus enqueueStatus = await checkResult.QueueTask; // this is the place task waits in queue // execution cancelled or queue timeout reached or queue full if (enqueueStatus != EnqueueStatus.AllowExecution && !context.RequestAborted.IsCancellationRequested) { var responseFeature = context.Features.Get <IHttpResponseFeature>(); responseFeature.StatusCode = StatusCodes.Status429TooManyRequests; responseFeature.ReasonPhrase = enqueueStatus.ToString(); return; } } try { await _next(context); } finally { _capacityGuard.FinishExecution(); } }
public CapacityCheckResult CheckCapacity(CancellationToken requestAbortedCancellationToken) { try { CancellationToken enqueueCancellationToken = GetEnqueueCancellationToken(requestAbortedCancellationToken); _guardSemaphore.Wait(enqueueCancellationToken); if (_concurrentRequestsCount < _throttlingConfiguration.ConcurrentRequestsLimit) { ++_concurrentRequestsCount; return(CapacityCheckResult.GetAllowed()); } return(CapacityCheckResult.GetQueued(Enqueue(enqueueCancellationToken))); } catch (OperationCanceledException) { return(CapacityCheckResult.GetCancelled()); } finally { _guardSemaphore.Release(); } }