From 42003a0247edf18395931a16911e02ea5a50a6c8 Mon Sep 17 00:00:00 2001 From: Jonnern <10881387+Jonnern@users.noreply.github.com> Date: Wed, 28 Aug 2024 12:25:09 +0200 Subject: [PATCH] Fix issue where SemaphoreSlim is released twice in RateLimitGate (#210) --- .../RateLimiting/RateLimitGate.cs | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/CryptoExchange.Net/RateLimiting/RateLimitGate.cs b/CryptoExchange.Net/RateLimiting/RateLimitGate.cs index cf12c96..2d1fed1 100644 --- a/CryptoExchange.Net/RateLimiting/RateLimitGate.cs +++ b/CryptoExchange.Net/RateLimiting/RateLimitGate.cs @@ -32,22 +32,30 @@ namespace CryptoExchange.Net.RateLimiting { _name = name; _guards = new ConcurrentBag(); - _semaphore = new SemaphoreSlim(1); + _semaphore = new SemaphoreSlim(1, 1); } /// public async Task ProcessAsync(ILogger logger, int itemId, RateLimitItemType type, RequestDefinition definition, string host, string? apiKey, int requestWeight, RateLimitingBehaviour rateLimitingBehaviour, CancellationToken ct) { await _semaphore.WaitAsync(ct).ConfigureAwait(false); + bool release = true; _waitingCount++; try { return await CheckGuardsAsync(_guards, logger, itemId, type, definition, host, apiKey, requestWeight, rateLimitingBehaviour, ct).ConfigureAwait(false); } + catch (TaskCanceledException) + { + // The semaphore has alraedy been released if the task was cancelled + release = false; + throw; + } finally { _waitingCount--; - _semaphore.Release(); + if (release) + _semaphore.Release(); } } @@ -64,16 +72,23 @@ namespace CryptoExchange.Net.RateLimiting CancellationToken ct) { await _semaphore.WaitAsync(ct).ConfigureAwait(false); - + bool release = true; _waitingCount++; try { return await CheckGuardsAsync(new IRateLimitGuard[] { guard }, logger, itemId, type, definition, host, apiKey, 1, rateLimitingBehaviour, ct).ConfigureAwait(false); } + catch (TaskCanceledException) + { + // The semaphore has alraedy been released if the task was cancelled + release = false; + throw; + } finally { _waitingCount--; - _semaphore.Release(); + if (release) + _semaphore.Release(); } }