Refactor periodic event loop

This commit is contained in:
Ske 2020-04-29 01:14:49 +02:00
parent 483a9d6ed9
commit 12aef1f61d

View File

@ -15,6 +15,8 @@ using DSharpPlus.EventArgs;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using NodaTime;
using PluralKit.Core; using PluralKit.Core;
using Sentry; using Sentry;
@ -106,7 +108,8 @@ namespace PluralKit.Bot
private ILogger _logger; private ILogger _logger;
private WebhookRateLimitService _webhookRateLimit; private WebhookRateLimitService _webhookRateLimit;
private int _periodicUpdateCount; private int _periodicUpdateCount;
private Task _periodicWorker;
public Bot(ILifetimeScope services, DiscordShardedClient client, IMetrics metrics, PeriodicStatCollector collector, ILogger logger, WebhookRateLimitService webhookRateLimit) public Bot(ILifetimeScope services, DiscordShardedClient client, IMetrics metrics, PeriodicStatCollector collector, ILogger logger, WebhookRateLimitService webhookRateLimit)
{ {
_services = services; _services = services;
@ -131,6 +134,9 @@ namespace PluralKit.Bot
_client.MessageUpdated += args => HandleEvent(eh => eh.HandleMessageEdited(args)); _client.MessageUpdated += args => HandleEvent(eh => eh.HandleMessageEdited(args));
_services.Resolve<ShardInfoService>().Init(_client); _services.Resolve<ShardInfoService>().Init(_client);
// Will not be awaited, just runs in the background
_periodicWorker = UpdatePeriodic();
return Task.CompletedTask; return Task.CompletedTask;
} }
@ -158,43 +164,40 @@ namespace PluralKit.Bot
_logger.Write(level, args.Exception, "D#+ {Source}: {Message}", args.Application, args.Message); _logger.Write(level, args.Exception, "D#+ {Source}: {Message}", args.Application, args.Message);
} }
// Method called every 60 seconds
private async Task UpdatePeriodic() private async Task UpdatePeriodic()
{ {
// Change bot status while (true)
var totalGuilds = _client.ShardClients.Values.Sum(c => c.Guilds.Count);
try // DiscordClient may throw an exception if the socket is closed (e.g just after OP 7 received)
{ {
await _client.UpdateStatusAsync(new DiscordActivity($"pk;help | in {totalGuilds} servers")); // Run at every whole minute (:00), mostly because I feel like it
} var timeNow = SystemClock.Instance.GetCurrentInstant();
catch (WebSocketException) { } var timeTillNextWholeMinute = 60000 - (timeNow.ToUnixTimeMilliseconds() % 60000);
await Task.Delay((int) timeTillNextWholeMinute);
// Change bot status
var totalGuilds = _client.ShardClients.Values.Sum(c => c.Guilds.Count);
try // DiscordClient may throw an exception if the socket is closed (e.g just after OP 7 received)
{
await _client.UpdateStatusAsync(new DiscordActivity($"pk;help | in {totalGuilds} servers"));
}
catch (WebSocketException) { }
// Run webhook rate limit GC every 10 minutes // Run webhook rate limit GC every 10 minutes
if (_periodicUpdateCount++ % 10 == 0) if (_periodicUpdateCount++ % 10 == 0)
{ {
var _ = Task.Run(() => _webhookRateLimit.GarbageCollect()); var _ = Task.Run(() => _webhookRateLimit.GarbageCollect());
} }
await _collector.CollectStats(); await _collector.CollectStats();
_logger.Information("Submitted metrics to backend"); _logger.Information("Submitted metrics to backend");
await Task.WhenAll(((IMetricsRoot) _metrics).ReportRunner.RunAllAsync()); await Task.WhenAll(((IMetricsRoot) _metrics).ReportRunner.RunAllAsync());
}
} }
private Task ShardReady(ReadyEventArgs e) private Task ShardReady(ReadyEventArgs e)
{ {
_logger.Information("Shard {Shard} connected to {ChannelCount} channels in {GuildCount} guilds", e.Client.ShardId, e.Client.Guilds.Sum(g => g.Value.Channels.Count), e.Client.Guilds.Count); _logger.Information("Shard {Shard} connected to {ChannelCount} channels in {GuildCount} guilds", e.Client.ShardId, e.Client.Guilds.Sum(g => g.Value.Channels.Count), e.Client.Guilds.Count);
if (e.Client.ShardId == 0)
{
_updateTimer = new Timer((_) => {
HandleEvent(_ => UpdatePeriodic());
}, null, TimeSpan.Zero, TimeSpan.FromMinutes(1));
_logger.Information("PluralKit started as {Username}#{Discriminator} ({Id})", _client.CurrentUser.Username, _client.CurrentUser.Discriminator, _client.CurrentUser.Id);
}
return Task.CompletedTask; return Task.CompletedTask;
} }