diff --git a/src/Discord.Net.Core/Net/Queue/RequestQueue.cs b/src/Discord.Net.Core/Net/Queue/RequestQueue.cs index ab20d7c18..1ea586481 100644 --- a/src/Discord.Net.Core/Net/Queue/RequestQueue.cs +++ b/src/Discord.Net.Core/Net/Queue/RequestQueue.cs @@ -79,7 +79,9 @@ namespace Discord.Net.Queue int millis = (int)Math.Ceiling((_waitUntil - DateTimeOffset.UtcNow).TotalMilliseconds); if (millis > 0) { +#if DEBUG_LIMITS Debug.WriteLine($"[{id}] Sleeping {millis} ms (Pre-emptive) [Global]"); +#endif await Task.Delay(millis).ConfigureAwait(false); } } diff --git a/src/Discord.Net.Core/Net/Queue/RequestQueueBucket.cs b/src/Discord.Net.Core/Net/Queue/RequestQueueBucket.cs index 6933730ff..59fbe51af 100644 --- a/src/Discord.Net.Core/Net/Queue/RequestQueueBucket.cs +++ b/src/Discord.Net.Core/Net/Queue/RequestQueueBucket.cs @@ -1,7 +1,9 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; +#if DEBUG_LIMITS using System.Diagnostics; +#endif using System.IO; using System.Net; using System.Threading; @@ -40,14 +42,18 @@ namespace Discord.Net.Queue public async Task SendAsync(RestRequest request) { int id = Interlocked.Increment(ref nextId); +#if DEBUG_LIMITS Debug.WriteLine($"[{id}] Start"); +#endif LastAttemptAt = DateTimeOffset.UtcNow; while (true) { await _queue.EnterGlobalAsync(id, request).ConfigureAwait(false); await EnterAsync(id, request).ConfigureAwait(false); +#if DEBUG_LIMITS Debug.WriteLine($"[{id}] Sending..."); +#endif var response = await request.SendAsync().ConfigureAwait(false); TimeSpan lag = DateTimeOffset.UtcNow - DateTimeOffset.Parse(response.Headers["Date"]); var info = new RateLimitInfo(response.Headers); @@ -59,18 +65,24 @@ namespace Discord.Net.Queue case (HttpStatusCode)429: if (info.IsGlobal) { +#if DEBUG_LIMITS Debug.WriteLine($"[{id}] (!) 429 [Global]"); +#endif _queue.PauseGlobal(info, lag); } else { +#if DEBUG_LIMITS Debug.WriteLine($"[{id}] (!) 429"); +#endif UpdateRateLimit(id, request, info, lag, true); } await _queue.RaiseRateLimitTriggered(Id, info).ConfigureAwait(false); continue; //Retry case HttpStatusCode.BadGateway: //502 +#if DEBUG_LIMITS Debug.WriteLine($"[{id}] (!) 502"); +#endif continue; //Continue default: string reason = null; @@ -92,9 +104,13 @@ namespace Discord.Net.Queue } else { +#if DEBUG_LIMITS Debug.WriteLine($"[{id}] Success"); +#endif UpdateRateLimit(id, request, info, lag, false); +#if DEBUG_LIMITS Debug.WriteLine($"[{id}] Stop"); +#endif return response.Stream; } } @@ -135,7 +151,9 @@ namespace Discord.Net.Queue if (resetAt > timeoutAt) throw new RateLimitedException(); int millis = (int)Math.Ceiling((resetAt.Value - DateTimeOffset.UtcNow).TotalMilliseconds); +#if DEBUG_LIMITS Debug.WriteLine($"[{id}] Sleeping {millis} ms (Pre-emptive)"); +#endif if (millis > 0) await Task.Delay(millis, request.CancelToken).ConfigureAwait(false); } @@ -143,13 +161,17 @@ namespace Discord.Net.Queue { if ((timeoutAt.Value - DateTimeOffset.UtcNow).TotalMilliseconds < 500.0) throw new RateLimitedException(); +#if DEBUG_LIMITS Debug.WriteLine($"[{id}] Sleeping 500* ms (Pre-emptive)"); +#endif await Task.Delay(500, request.CancelToken).ConfigureAwait(false); } continue; } +#if DEBUG_LIMITS else Debug.WriteLine($"[{id}] Entered Semaphore ({_semaphore}/{WindowCount} remaining)"); +#endif break; } } @@ -166,7 +188,9 @@ namespace Discord.Net.Queue { WindowCount = info.Limit.Value; _semaphore = info.Remaining.Value; +#if DEBUG_LIMITS Debug.WriteLine($"[{id}] Upgraded Semaphore to {info.Remaining.Value}/{WindowCount}"); +#endif } var now = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); @@ -182,24 +206,32 @@ namespace Discord.Net.Queue { //RetryAfter is more accurate than Reset, where available resetTick = DateTimeOffset.UtcNow.AddMilliseconds(info.RetryAfter.Value); +#if DEBUG_LIMITS Debug.WriteLine($"[{id}] Retry-After: {info.RetryAfter.Value} ({info.RetryAfter.Value} ms)"); +#endif } else if (info.Reset.HasValue) { resetTick = info.Reset.Value.AddSeconds(/*1.0 +*/ lag.TotalSeconds); int diff = (int)(resetTick.Value - DateTimeOffset.UtcNow).TotalMilliseconds; +#if DEBUG_LIMITS Debug.WriteLine($"[{id}] X-RateLimit-Reset: {info.Reset.Value.ToUnixTimeSeconds()} ({diff} ms, {lag.TotalMilliseconds} ms lag)"); +#endif } else if (request.Options.ClientBucketId != null) { resetTick = DateTimeOffset.UtcNow.AddSeconds(ClientBucket.Get(request.Options.ClientBucketId).WindowSeconds); +#if DEBUG_LIMITS Debug.WriteLine($"[{id}] Client Bucket ({ClientBucket.Get(request.Options.ClientBucketId).WindowSeconds * 1000} ms)"); +#endif } if (resetTick == null) { WindowCount = 0; //No rate limit info, disable limits on this bucket (should only ever happen with a user token) +#if DEBUG_LIMITS Debug.WriteLine($"[{id}] Disabled Semaphore"); +#endif return; } @@ -207,7 +239,9 @@ namespace Discord.Net.Queue { _resetTick = resetTick; LastAttemptAt = resetTick.Value; //Make sure we dont destroy this until after its been reset +#if DEBUG_LIMITS Debug.WriteLine($"[{id}] Reset in {(int)Math.Ceiling((resetTick - DateTimeOffset.UtcNow).Value.TotalMilliseconds)} ms"); +#endif if (!hasQueuedReset) { @@ -227,7 +261,9 @@ namespace Discord.Net.Queue millis = (int)Math.Ceiling((_resetTick.Value - DateTimeOffset.UtcNow).TotalMilliseconds); if (millis <= 0) //Make sure we havent gotten a more accurate reset time { +#if DEBUG_LIMITS Debug.WriteLine($"[{id}] * Reset *"); +#endif _semaphore = WindowCount; _resetTick = null; return;