ConcurrencyLimiter: a waiter cancelled during a release can leave a free permit that a queued request never gets
Maintainer thường phản hồi trong vòng 1 ngày
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức phù hợp với người mới
- 55/100
Hướng nghiên cứu
Start with ConcurrencyLimiter and its queue-processing and cancellation paths; the issue provides a self-contained reproduction using OldestFirst. Run the reproduction or add a focused regression test for the cancellation, release, and new-acquire interleaving. Done when the queued request receives the free permit and the regression test passes.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Description
With QueueProcessingOrder.OldestFirst, a ConcurrencyLimiter can end up with a free permit and a queued request that never gets it. No lease is held, so no Release ever comes to hand the permit out. The queued request waits until its own token is cancelled, and AttemptAcquire is refused while it waits.
It happens when three things coincide: a queued waiter's token is cancelled, the permit holder releases, and a new AcquireAsync arrives.
Reproduction Steps
using System.Diagnostics;
using System.Threading.RateLimiting;
// One permit, queue of 2, oldest first. Each round: A holds the permit and B waits with a token.
// Then, at the same moment, B's token is cancelled, A releases, and C calls AcquireAsync. However
// those three interleave, C should end up holding the permit, since nothing else does.
var budget = Stopwatch.StartNew();
for (var round = 1; budget.Elapsed < TimeSpan.FromMinutes(2); round++)
{
var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions
{
PermitLimit = 1,
QueueLimit = 2,
QueueProcessingOrder = QueueProcessingOrder.OldestFirst,
});
var a = limiter.AttemptAcquire();
using var cts = new CancellationTokenSource();
var b = limiter.AcquireAsync(1, cts.Token).AsTask();
using var start = new Barrier(3);
Task<RateLimitLease>? c = null;
await Task.WhenAll(
Task.Run(() => { start.SignalAndWait(); cts.Cancel(); }),
Task.Run(() => { start.SignalAndWait(); a.Dispose(); }),
Task.Run(() => { start.SignalAndWait(); c = limiter.AcquireAsync(1).AsTask(); }));
try { (await b).Dispose(); } catch (OperationCanceledException) { }
if (await Task.WhenAny(c!, Task.Delay(TimeSpan.FromSeconds(1))) != c)
{
var stats = limiter.GetStatistics()!;
Console.WriteLine($"Round {round}: C still waiting after 1 s, with nothing holding a permit.");
Console.WriteLine($" CurrentAvailablePermits = {stats.CurrentAvailablePermits}, CurrentQueuedCount = {stats.CurrentQueuedCount}");
Console.WriteLine($" A new AttemptAcquire is granted: {limiter.AttemptAcquire().IsAcquired}");
return 1;
}
(await c!).Dispose();
}
Console.WriteLine("No stall within 2 minutes.");
return 0;
Output:
Round 17524: C still waiting after 1 s, with nothing holding a permit.
CurrentAvailablePermits = 1, CurrentQueuedCount = 1
A new AttemptAcquire is granted: False
Expected behavior
C is granted the permit, since nothing else holds it.
Actual behavior
The permit stays available and C stays queued until its own token is cancelled. With steady traffic, each new request queues behind the free permit and times out, so the limiter grants nothing until no request is queued.
Regression?
No response
Known Workarounds
No response
Configuration
Windows 11 x64
Repro'd on both .NET 11 and 10
Other information
No response
- Ngôn ngữ chính
- C#
- Star
- 18.4k
- Fork
- 5.8k
- Merge trung bình
- 2 ngày 12 giờ
- Pull request đã merge (30 ngày)
- 600
Chuẩn bị môi trường
Khởi chạy dev container của dự án ngay trên trình duyệt, bằng tài khoản GitHub của bạn.
- Không có Dockerfile hay tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của dotnet/runtime
-
area-System.IO untriaged
Độ khó 2/5 Nửa ngày Mức phù hợp với người mới 72/100
dotnet/runtime#136802 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
[wasi] .NET 10: WasmEnableSIMD with AOT fails because WasiApp.targets has -msimd128 commented outĐang mởarea-Build-mono untriaged
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
Maintainer thường phản hồi trong vòng 1 ngày
-
area-System.ComponentModel untriaged
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 65/100
dotnet/runtime#136608 · 2 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
MemoryMappedFile (Windows): failed MEM_COMMIT is ignored, accessor over reserved memory crashes the processCó thể đã có người làm @RutulPatel8 đã nhận hôm nay. Đang mởarea-System.IO bug untriaged
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
dotnet/runtime#136599 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
area-System.IO untriaged
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
dotnet/runtime#136577 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của dotnet/runtime
Issue tương tự
-
effort:S P3 refactor
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
nightscout/nocturne#3243 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
dasher-project/Dasher-Windows#84 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 70/100
libnativeapi/nativeapi#21 ·
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
Maintainer thường phản hồi trong vòng 3 ngày
-
enhancement P3 performance
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
thomhurst/TUnit#7380 · 2 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày