fix: Incomplete Ready, DownloadUsersAsync, and optimize AlwaysDownloadUsers (#1548)
* Fix Ready and AlwaysDownloadUsers Ready could fire before downloading all guild data and downloading guild users one guild per time without gateway intents is a waste of a gateway request that can support up to 1000. * Reduce batchSize and fix count * Fix typo * Split xml docs line Co-authored-by: Christopher Felegy <cfelegy@riseup.net>
This commit is contained in:
@@ -21,7 +21,13 @@ namespace Discord.WebSocket
|
|||||||
remove { _disconnectedEvent.Remove(value); }
|
remove { _disconnectedEvent.Remove(value); }
|
||||||
}
|
}
|
||||||
private readonly AsyncEvent<Func<Exception, Task>> _disconnectedEvent = new AsyncEvent<Func<Exception, Task>>();
|
private readonly AsyncEvent<Func<Exception, Task>> _disconnectedEvent = new AsyncEvent<Func<Exception, Task>>();
|
||||||
/// <summary> Fired when guild data has finished downloading. </summary>
|
/// <summary>
|
||||||
|
/// Fired when guild data has finished downloading.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// It is possible that some guilds might be unsynced if <see cref="DiscordSocketConfig.MaxWaitBetweenGuildAvailablesBeforeReady" />
|
||||||
|
/// was not long enough to receive all GUILD_AVAILABLEs before READY.
|
||||||
|
/// </remarks>
|
||||||
public event Func<Task> Ready
|
public event Func<Task> Ready
|
||||||
{
|
{
|
||||||
add { _readyEvent.Add(value); }
|
add { _readyEvent.Add(value); }
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ namespace Discord.WebSocket
|
|||||||
|
|
||||||
GuildAvailable += g =>
|
GuildAvailable += g =>
|
||||||
{
|
{
|
||||||
if (ConnectionState == ConnectionState.Connected && AlwaysDownloadUsers && !g.HasAllMembers)
|
if (_guildDownloadTask?.IsCompleted == true && ConnectionState == ConnectionState.Connected && AlwaysDownloadUsers && !g.HasAllMembers)
|
||||||
{
|
{
|
||||||
var _ = g.DownloadUsersAsync();
|
var _ = g.DownloadUsersAsync();
|
||||||
}
|
}
|
||||||
@@ -370,7 +370,7 @@ namespace Discord.WebSocket
|
|||||||
{
|
{
|
||||||
var cachedGuilds = guilds.ToImmutableArray();
|
var cachedGuilds = guilds.ToImmutableArray();
|
||||||
|
|
||||||
const short batchSize = 50;
|
const short batchSize = 100; //TODO: Gateway Intents will limit to a maximum of 1 guild_id
|
||||||
ulong[] batchIds = new ulong[Math.Min(batchSize, cachedGuilds.Length)];
|
ulong[] batchIds = new ulong[Math.Min(batchSize, cachedGuilds.Length)];
|
||||||
Task[] batchTasks = new Task[batchIds.Length];
|
Task[] batchTasks = new Task[batchIds.Length];
|
||||||
int batchCount = (cachedGuilds.Length + (batchSize - 1)) / batchSize;
|
int batchCount = (cachedGuilds.Length + (batchSize - 1)) / batchSize;
|
||||||
@@ -378,7 +378,7 @@ namespace Discord.WebSocket
|
|||||||
for (int i = 0, k = 0; i < batchCount; i++)
|
for (int i = 0, k = 0; i < batchCount; i++)
|
||||||
{
|
{
|
||||||
bool isLast = i == batchCount - 1;
|
bool isLast = i == batchCount - 1;
|
||||||
int count = isLast ? (batchIds.Length - (batchCount - 1) * batchSize) : batchSize;
|
int count = isLast ? (cachedGuilds.Length - (batchCount - 1) * batchSize) : batchSize;
|
||||||
|
|
||||||
for (int j = 0; j < count; j++, k++)
|
for (int j = 0; j < count; j++, k++)
|
||||||
{
|
{
|
||||||
@@ -579,6 +579,9 @@ namespace Discord.WebSocket
|
|||||||
else if (_connection.CancelToken.IsCancellationRequested)
|
else if (_connection.CancelToken.IsCancellationRequested)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (BaseConfig.AlwaysDownloadUsers)
|
||||||
|
_ = DownloadUsersAsync(Guilds.Where(x => x.IsAvailable && !x.HasAllMembers));
|
||||||
|
|
||||||
await TimedInvokeAsync(_readyEvent, nameof(Ready)).ConfigureAwait(false);
|
await TimedInvokeAsync(_readyEvent, nameof(Ready)).ConfigureAwait(false);
|
||||||
await _gatewayLogger.InfoAsync("Ready").ConfigureAwait(false);
|
await _gatewayLogger.InfoAsync("Ready").ConfigureAwait(false);
|
||||||
});
|
});
|
||||||
@@ -1772,7 +1775,7 @@ namespace Discord.WebSocket
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
await logger.DebugAsync("GuildDownloader Started").ConfigureAwait(false);
|
await logger.DebugAsync("GuildDownloader Started").ConfigureAwait(false);
|
||||||
while ((_unavailableGuildCount != 0) && (Environment.TickCount - _lastGuildAvailableTime < 2000))
|
while ((_unavailableGuildCount != 0) && (Environment.TickCount - _lastGuildAvailableTime < BaseConfig.MaxWaitBetweenGuildAvailablesBeforeReady))
|
||||||
await Task.Delay(500, cancelToken).ConfigureAwait(false);
|
await Task.Delay(500, cancelToken).ConfigureAwait(false);
|
||||||
await logger.DebugAsync("GuildDownloader Stopped").ConfigureAwait(false);
|
await logger.DebugAsync("GuildDownloader Stopped").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,6 +126,31 @@ namespace Discord.WebSocket
|
|||||||
public bool GuildSubscriptions { get; set; } = true;
|
public bool GuildSubscriptions { get; set; } = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
/// Gets or sets the maximum wait time in milliseconds between GUILD_AVAILABLE events before firing READY.
|
||||||
|
///
|
||||||
|
/// If zero, READY will fire as soon as it is received and all guilds will be unavailable.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>This property is measured in milliseconds, negative values will throw an exception.</para>
|
||||||
|
/// <para>If a guild is not received before READY, it will be unavailable.</para>
|
||||||
|
/// </remarks>
|
||||||
|
/// <returns>
|
||||||
|
/// The maximum wait time in milliseconds between GUILD_AVAILABLE events before firing READY.
|
||||||
|
/// </returns>
|
||||||
|
/// <exception cref="System.ArgumentException">Value must be at least 0.</exception>
|
||||||
|
public int MaxWaitBetweenGuildAvailablesBeforeReady {
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _maxWaitForGuildAvailable;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
Preconditions.AtLeast(value, 0, nameof(MaxWaitBetweenGuildAvailablesBeforeReady));
|
||||||
|
_maxWaitForGuildAvailable = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private int _maxWaitForGuildAvailable = 10000;
|
||||||
|
|
||||||
/// Gets or sets gateway intents to limit what events are sent from Discord. Allows for more granular control than the <see cref="GuildSubscriptions"/> property.
|
/// Gets or sets gateway intents to limit what events are sent from Discord. Allows for more granular control than the <see cref="GuildSubscriptions"/> property.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
|
|||||||
Reference in New Issue
Block a user