diff --git a/src/Discord.Net.Core/Net/BucketId.cs b/src/Discord.Net.Core/Net/BucketId.cs index 27df5e0ce..96281a0ed 100644 --- a/src/Discord.Net.Core/Net/BucketId.cs +++ b/src/Discord.Net.Core/Net/BucketId.cs @@ -51,7 +51,7 @@ namespace Discord.Net /// Major parameters of the route of this endpoint. /// /// A based on the - /// and the with the provided data. + /// and the with the provided data. /// public static BucketId Create(string httpMethod, string endpoint, Dictionary majorParams) { diff --git a/src/Discord.Net.Rest/DiscordRestApiClient.cs b/src/Discord.Net.Rest/DiscordRestApiClient.cs index c2be2b094..39de67147 100644 --- a/src/Discord.Net.Rest/DiscordRestApiClient.cs +++ b/src/Discord.Net.Rest/DiscordRestApiClient.cs @@ -1490,7 +1490,6 @@ namespace Discord.API private static BucketId GetBucketId(string httpMethod, BucketIds ids, Expression> endpointExpr, string callingMethod) { ids.HttpMethod ??= httpMethod; - Debug.WriteLine("GetBucketId: " + CreateBucketId(endpointExpr)(ids)); return _bucketIdGenerators.GetOrAdd(callingMethod, x => CreateBucketId(endpointExpr))(ids); } diff --git a/src/Discord.Net.Rest/Net/Queue/RequestQueueBucket.cs b/src/Discord.Net.Rest/Net/Queue/RequestQueueBucket.cs index 682f8383f..275533e8b 100644 --- a/src/Discord.Net.Rest/Net/Queue/RequestQueueBucket.cs +++ b/src/Discord.Net.Rest/Net/Queue/RequestQueueBucket.cs @@ -33,7 +33,7 @@ namespace Discord.Net.Queue _lock = new object(); if (request.Options.IsClientBucket) - WindowCount = ClientBucket.Get(request.Options.BucketId).WindowCount; + WindowCount = ClientBucket.Get(Id).WindowCount; else WindowCount = 1; //Only allow one request until we get a header back _semaphore = WindowCount; @@ -181,7 +181,8 @@ namespace Discord.Net.Queue } DateTimeOffset? timeoutAt = request.TimeoutAt; - if (windowCount > 0 && Interlocked.Decrement(ref _semaphore) < 0) + int semaphore = 0; + if (windowCount > 0 && (semaphore = Interlocked.Decrement(ref _semaphore)) < 0) { if (!isRateLimited) { @@ -216,7 +217,7 @@ namespace Discord.Net.Queue } #if DEBUG_LIMITS else - Debug.WriteLine($"[{id}] Entered Semaphore ({_semaphore}/{WindowCount} remaining)"); + Debug.WriteLine($"[{id}] Entered Semaphore ({semaphore}/{WindowCount} remaining)"); #endif break; } @@ -230,31 +231,47 @@ namespace Discord.Net.Queue lock (_lock) { if (redirected) - Interlocked.Decrement(ref _semaphore); //we might still hit a real ratelimit if all tickets were already taken, can't do much about it since we didn't know they were the same - bool hasQueuedReset = _resetTick != null; - if (info.Limit.HasValue && WindowCount != info.Limit.Value) { - WindowCount = info.Limit.Value; - _semaphore = info.Remaining.Value; + Interlocked.Decrement(ref _semaphore); //we might still hit a real ratelimit if all tickets were already taken, can't do much about it since we didn't know they were the same #if DEBUG_LIMITS - Debug.WriteLine($"[{id}] Upgraded Semaphore to {info.Remaining.Value}/{WindowCount}"); + Debug.WriteLine($"[{id}] Decrease Semaphore"); #endif } + bool hasQueuedReset = _resetTick != null; if (info.Bucket != null && !redirected) { - (RequestBucket, BucketId) hashBucket = _queue.UpdateBucketHash(request.Options.BucketId, info.Bucket); - if (hashBucket.Item1 is null || hashBucket.Item2 is null) - return; - if (hashBucket.Item1 == this) //this bucket got promoted to a hash queue - Id = hashBucket.Item2; - else + (RequestBucket, BucketId) hashBucket = _queue.UpdateBucketHash(Id, info.Bucket); + if (!(hashBucket.Item1 is null) && !(hashBucket.Item2 is null)) { - _redirectBucket = hashBucket.Item1; //this request should be part of another bucket, this bucket will be disabled, redirect everything - _redirectBucket.UpdateRateLimit(id, request, info, is429, redirected: true); //update the hash bucket ratelimit + if (hashBucket.Item1 == this) //this bucket got promoted to a hash queue + { + Id = hashBucket.Item2; +#if DEBUG_LIMITS + Debug.WriteLine($"[{id}] Promoted to Hash Bucket ({hashBucket.Item2})"); +#endif + } + else + { + _redirectBucket = hashBucket.Item1; //this request should be part of another bucket, this bucket will be disabled, redirect everything + _redirectBucket.UpdateRateLimit(id, request, info, is429, redirected: true); //update the hash bucket ratelimit +#if DEBUG_LIMITS + Debug.WriteLine($"[{id}] Redirected to {_redirectBucket.Id}"); +#endif + return; + } } } + if (info.Limit.HasValue && WindowCount != info.Limit.Value) + { + WindowCount = info.Limit.Value; + _semaphore = info.Remaining.Value; +#if DEBUG_LIMITS + Debug.WriteLine($"[{id}] Upgraded Semaphore to {info.Remaining.Value}/{WindowCount}"); +#endif + } + DateTimeOffset? resetTick = null; //Using X-RateLimit-Remaining causes a race condition @@ -289,11 +306,11 @@ namespace Discord.Net.Queue Debug.WriteLine($"[{id}] X-RateLimit-Reset: {info.Reset.Value.ToUnixTimeSeconds()} ({diff} ms, {info.Lag?.TotalMilliseconds} ms lag)"); #endif } - else if (request.Options.IsClientBucket && request.Options.BucketId != null) + else if (request.Options.IsClientBucket && Id != null) { - resetTick = DateTimeOffset.UtcNow.AddSeconds(ClientBucket.Get(request.Options.BucketId).WindowSeconds); + resetTick = DateTimeOffset.UtcNow.AddSeconds(ClientBucket.Get(Id).WindowSeconds); #if DEBUG_LIMITS - Debug.WriteLine($"[{id}] Client Bucket ({ClientBucket.Get(request.Options.BucketId).WindowSeconds * 1000} ms)"); + Debug.WriteLine($"[{id}] Client Bucket ({ClientBucket.Get(Id).WindowSeconds * 1000} ms)"); #endif }