feat: tweak embed dequeueing logic
We no longer blindly dequeue 5 embeds, we check their length too. The webhook executor will now send up to 10 embeds OR embeds totaling less than 6000 characters, whichever is less. Embeds longer than 6000 characters are discarded to prevent errors. We also check for an empty request body in SendLogAsync and bail to prevent 400s.
This commit is contained in:
parent
f524afb05b
commit
d221441c10
2 changed files with 62 additions and 10 deletions
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Catalogger.Backend.Cache;
|
||||
using Catalogger.Backend.Cache.InMemoryCache;
|
||||
using Catalogger.Backend.Extensions;
|
||||
|
|
@ -11,6 +12,11 @@ using Guild = Catalogger.Backend.Database.Models.Guild;
|
|||
|
||||
namespace Catalogger.Backend.Services;
|
||||
|
||||
[SuppressMessage(
|
||||
"ReSharper",
|
||||
"InconsistentlySynchronizedField",
|
||||
Justification = "ILogger doesn't need to be synchronized"
|
||||
)]
|
||||
public class WebhookExecutorService(
|
||||
Config config,
|
||||
ILogger logger,
|
||||
|
|
@ -76,6 +82,14 @@ public class WebhookExecutorService(
|
|||
.Select<FileData, OneOf.OneOf<FileData, IPartialAttachment>>(f => f)
|
||||
.ToList();
|
||||
|
||||
if (embeds.Count == 0 && attachments.Count == 0)
|
||||
{
|
||||
_logger.Error(
|
||||
"SendLogAsync was called with zero embeds and zero attachments, bailing to prevent a bad request error"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
_logger.Debug(
|
||||
"Sending {EmbedCount} embeds/{FileCount} files to channel {ChannelId}",
|
||||
embeds.Count,
|
||||
|
|
@ -108,9 +122,7 @@ public class WebhookExecutorService(
|
|||
_timers[channelId] = new Timer(
|
||||
_ =>
|
||||
{
|
||||
_logger.Debug("Sending 5 queued embeds");
|
||||
|
||||
var __ = SendLogAsync(channelId, TakeFromQueue(channelId).ToList(), []);
|
||||
var __ = SendLogAsync(channelId, TakeFromQueue(channelId), []);
|
||||
if (!queue.IsEmpty)
|
||||
{
|
||||
if (_timers.TryGetValue(channelId, out var timer))
|
||||
|
|
@ -124,8 +136,11 @@ public class WebhookExecutorService(
|
|||
);
|
||||
}
|
||||
|
||||
private const int MaxContentLength = 6000;
|
||||
|
||||
/// <summary>
|
||||
/// Takes 5 embeds from the queue for the given channel.
|
||||
/// Takes as many embeds as possible from the queue for the given channel.
|
||||
/// Up to ten embeds are returned, or less if their combined length is longer than 6000 characters.
|
||||
/// Note that this locks the queue to prevent duplicate embeds from being sent.
|
||||
/// </summary>
|
||||
private List<IEmbed> TakeFromQueue(ulong channelId)
|
||||
|
|
@ -134,14 +149,43 @@ public class WebhookExecutorService(
|
|||
var channelLock = _locks.GetOrAdd(channelId, channelId);
|
||||
lock (channelLock)
|
||||
{
|
||||
var totalContentLength = 0;
|
||||
var embeds = new List<IEmbed>();
|
||||
for (var i = 0; i < 5; i++)
|
||||
while (embeds.Count < 10 && totalContentLength < MaxContentLength)
|
||||
{
|
||||
if (!queue.TryDequeue(out var embed))
|
||||
if (!queue.TryPeek(out var embed))
|
||||
break;
|
||||
|
||||
var length = embed.TextLength();
|
||||
if (length > MaxContentLength)
|
||||
{
|
||||
_logger.Warning(
|
||||
"Queued embed for {ChannelId} exceeds maximum length, discarding it",
|
||||
channelId
|
||||
);
|
||||
queue.TryDequeue(out _);
|
||||
break;
|
||||
}
|
||||
|
||||
if (totalContentLength + length > MaxContentLength)
|
||||
break;
|
||||
|
||||
totalContentLength += length;
|
||||
|
||||
queue.TryDequeue(out _);
|
||||
embeds.Add(embed);
|
||||
}
|
||||
|
||||
if (embeds.Count == 0)
|
||||
return embeds;
|
||||
|
||||
_logger.Debug(
|
||||
"Took {EmbedCount} embeds from queue for {ChannelId}, total length is {TotalLength}",
|
||||
embeds.Count,
|
||||
channelId,
|
||||
totalContentLength
|
||||
);
|
||||
|
||||
return embeds;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue