From 93bf7c65434fa53ae456c6b2f4b504a4ca553468 Mon Sep 17 00:00:00 2001 From: Ske Date: Thu, 16 Apr 2020 18:18:08 +0200 Subject: [PATCH] Add periodic garbage collection of webhook rate limit cache --- PluralKit.Bot/Bot.cs | 13 +++++++++++-- .../Services/WebhookRateLimitService.cs | 17 +++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/PluralKit.Bot/Bot.cs b/PluralKit.Bot/Bot.cs index 940e137d..ff4b4fdd 100644 --- a/PluralKit.Bot/Bot.cs +++ b/PluralKit.Bot/Bot.cs @@ -102,13 +102,16 @@ namespace PluralKit.Bot private IMetrics _metrics; private PeriodicStatCollector _collector; private ILogger _logger; + private WebhookRateLimitService _webhookRateLimit; + private int _periodicUpdateCount; - public Bot(ILifetimeScope services, IDiscordClient client, IMetrics metrics, PeriodicStatCollector collector, ILogger logger) + public Bot(ILifetimeScope services, IDiscordClient client, IMetrics metrics, PeriodicStatCollector collector, ILogger logger, WebhookRateLimitService webhookRateLimit) { _services = services; _client = client as DiscordShardedClient; _metrics = metrics; _collector = collector; + _webhookRateLimit = webhookRateLimit; _logger = logger.ForContext(); } @@ -161,7 +164,13 @@ namespace PluralKit.Bot { // Change bot status await _client.SetGameAsync($"pk;help | in {_client.Guilds.Count} servers"); - + + // Run webhook rate limit GC every 10 minutes + if (_periodicUpdateCount++ % 10 == 0) + { + var _ = Task.Run(() => _webhookRateLimit.GarbageCollect()); + } + await _collector.CollectStats(); _logger.Information("Submitted metrics to backend"); diff --git a/PluralKit.Bot/Services/WebhookRateLimitService.cs b/PluralKit.Bot/Services/WebhookRateLimitService.cs index 0dddd9d3..28c2477a 100644 --- a/PluralKit.Bot/Services/WebhookRateLimitService.cs +++ b/PluralKit.Bot/Services/WebhookRateLimitService.cs @@ -87,6 +87,23 @@ namespace PluralKit.Bot } } + public void GarbageCollect() + { + _logger.Information("Garbage-collecting webhook rate limit buckets..."); + + var collected = 0; + foreach (var channel in _info.Keys) + { + if (!_info.TryGetValue(channel, out var info)) continue; + + // Remove all keys that expired more than an hour ago (and of course, haven't been reset) + if (info.resetTime < SystemClock.Instance.GetCurrentInstant() - Duration.FromHours(1)) + if (_info.TryRemove(channel, out _)) collected++; + } + + _logger.Information("Garbage-collected {ChannelCount} channels from the webhook rate limit buckets.", collected); + } + private string GetHeader(HttpResponseMessage response, string key) { var firstPair = response.Headers.FirstOrDefault(pair => pair.Key.Equals(key, StringComparison.InvariantCultureIgnoreCase));