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.
This commit is contained in:
Noi 2020-07-27 22:30:15 -07:00
parent a87426a5f6
commit 657181ec3e
2 changed files with 39 additions and 3 deletions

View file

@ -23,9 +23,11 @@ namespace BirthdayBot.BackgroundServices
public override async Task OnTick() public override async Task OnTick()
{ {
var tasks = new List<Task>(); var tasks = new List<Task>();
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); var alltasks = Task.WhenAll(tasks);
@ -60,6 +62,39 @@ namespace BirthdayBot.BackgroundServices
/// <returns>Diagnostic data in string form.</returns> /// <returns>Diagnostic data in string form.</returns>
public async Task<string> SingleProcessGuildAsync(SocketGuild guild) => (await ProcessGuildAsync(guild)).Export(); public async Task<string> SingleProcessGuildAsync(SocketGuild guild) => (await ProcessGuildAsync(guild)).Export();
/// <summary>
/// Called by <see cref="OnTick"/>, processes all guilds within a shard synchronously.
/// </summary>
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<Exception>();
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);
}
/// <summary> /// <summary>
/// Main method where actual guild processing occurs. /// Main method where actual guild processing occurs.
/// </summary> /// </summary>
@ -78,7 +113,7 @@ namespace BirthdayBot.BackgroundServices
if (diag.RoleCheck != null) return diag; if (diag.RoleCheck != null) return diag;
// Determine who's currently having a birthday // Determine who's currently having a birthday
await guild.DownloadUsersAsync(); //await guild.DownloadUsersAsync();
var users = await GuildUserConfiguration.LoadAllAsync(guild.Id); var users = await GuildUserConfiguration.LoadAllAsync(guild.Id);
var tz = gc.TimeZone; var tz = gc.TimeZone;
var birthdays = GetGuildCurrentBirthdays(users, tz); var birthdays = GetGuildCurrentBirthdays(users, tz);

View file

@ -21,6 +21,7 @@ namespace BirthdayBot
var dc = new DiscordSocketConfig() var dc = new DiscordSocketConfig()
{ {
AlwaysDownloadUsers = true,
DefaultRetryMode = RetryMode.RetryRatelimit, DefaultRetryMode = RetryMode.RetryRatelimit,
MessageCacheSize = 0, MessageCacheSize = 0,
TotalShards = cfg.ShardCount, TotalShards = cfg.ShardCount,