From 657181ec3ed40bce93ea44ad5e3e73be11115500 Mon Sep 17 00:00:00 2001 From: Noi Date: Mon, 27 Jul 2020 22:30:15 -0700 Subject: [PATCH] Less async birthday updates; download users on connect From testing, it appears DownloadUsersAsync hangs forever and has other consequences if its corresponding server is not fully connected, or is struggling to connect. This is despite all attempts to mitigate it and detect any disconnections shortly before attempting it. Additionally, birthday updates are now run asynchronously per shard, but synchronously per guild in an attempt to keep rare instances of rate limiting under control. --- BackgroundServices/BirthdayRoleUpdate.cs | 41 ++++++++++++++++++++++-- Program.cs | 1 + 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/BackgroundServices/BirthdayRoleUpdate.cs b/BackgroundServices/BirthdayRoleUpdate.cs index 94a22ae..0675cd2 100644 --- a/BackgroundServices/BirthdayRoleUpdate.cs +++ b/BackgroundServices/BirthdayRoleUpdate.cs @@ -23,9 +23,11 @@ namespace BirthdayBot.BackgroundServices public override async Task OnTick() { var tasks = new List(); - foreach (var guild in BotInstance.DiscordClient.Guilds) + + // Work on each shard concurrently; guilds within each shard synchronously + foreach (var shard in BotInstance.DiscordClient.Shards) { - tasks.Add(ProcessGuildAsync(guild)); + tasks.Add(ProcessShardAsync(shard)); } var alltasks = Task.WhenAll(tasks); @@ -60,6 +62,39 @@ namespace BirthdayBot.BackgroundServices /// Diagnostic data in string form. public async Task SingleProcessGuildAsync(SocketGuild guild) => (await ProcessGuildAsync(guild)).Export(); + /// + /// Called by , processes all guilds within a shard synchronously. + /// + private async Task ProcessShardAsync(DiscordSocketClient shard) + { + if (shard.ConnectionState != Discord.ConnectionState.Connected) + { + Log($"Shard {shard.ShardId} (with {shard.Guilds.Count} guilds) processing stopped - shard disconnected."); + return; + } + var exs = new List(); + foreach (var guild in shard.Guilds) + { + try + { + // Check if shard remains available + if (shard.ConnectionState != Discord.ConnectionState.Connected) + { + Log($"Shard {shard.ShardId} (with {shard.Guilds.Count} guilds) processing interrupted."); + return; + } + await ProcessGuildAsync(guild); + } + catch (Exception ex) + { + // Catch all exceptions per-guild but continue processing, throw at end + exs.Add(ex); + } + } + Log($"Shard {shard.ShardId} (with {shard.Guilds.Count} guilds) processing completed."); + if (exs.Count != 0) throw new AggregateException(exs); + } + /// /// Main method where actual guild processing occurs. /// @@ -78,7 +113,7 @@ namespace BirthdayBot.BackgroundServices if (diag.RoleCheck != null) return diag; // Determine who's currently having a birthday - await guild.DownloadUsersAsync(); + //await guild.DownloadUsersAsync(); var users = await GuildUserConfiguration.LoadAllAsync(guild.Id); var tz = gc.TimeZone; var birthdays = GetGuildCurrentBirthdays(users, tz); diff --git a/Program.cs b/Program.cs index 0281b71..085c49c 100644 --- a/Program.cs +++ b/Program.cs @@ -21,6 +21,7 @@ namespace BirthdayBot var dc = new DiscordSocketConfig() { + AlwaysDownloadUsers = true, DefaultRetryMode = RetryMode.RetryRatelimit, MessageCacheSize = 0, TotalShards = cfg.ShardCount,