feat: block running commands / proxying when system is being deleted

Large systems take way too long to delete, which causes any insert for that system to block a connection, which exhausts the connection pool
This commit is contained in:
spiral 2022-03-23 21:32:18 -04:00
parent 375e650c9e
commit be89f907a0
No known key found for this signature in database
GPG Key ID: 244A11E4B0BCF40E
7 changed files with 31 additions and 3 deletions

View File

@ -10,4 +10,6 @@ public record MessageRequest
public AllowedMentions? AllowedMentions { get; set; } public AllowedMentions? AllowedMentions { get; set; }
public Embed[]? Embeds { get; set; } public Embed[]? Embeds { get; set; }
public MessageComponent[]? Components { get; set; } public MessageComponent[]? Components { get; set; }
public Message.Reference? MessageReference { get; set; }
} }

View File

@ -120,6 +120,17 @@ public class MessageCreated: IEventHandler<MessageCreateEvent>
if (!HasCommandPrefix(content, ourUserId, out var cmdStart) || cmdStart == content.Length) if (!HasCommandPrefix(content, ourUserId, out var cmdStart) || cmdStart == content.Length)
return false; return false;
if (ctx.IsDeleting)
{
await _rest.CreateMessage(evt.ChannelId, new()
{
Content = $"{Emojis.Error} Your system is currently being deleted."
+ " Due to database issues, it is not possible to use commands while a system is being deleted. Please wait a few minutes and try again.",
MessageReference = new(guild?.Id, channel.Id, evt.Id)
});
return true;
}
// Trim leading whitespace from command without actually modifying the string // Trim leading whitespace from command without actually modifying the string
// This just moves the argPos pointer by however much whitespace is at the start of the post-argPos string // This just moves the argPos pointer by however much whitespace is at the start of the post-argPos string
var trimStartLengthDiff = var trimStartLengthDiff =
@ -164,6 +175,8 @@ public class MessageCreated: IEventHandler<MessageCreateEvent>
private async ValueTask<bool> TryHandleProxy(MessageCreateEvent evt, Guild guild, Channel channel, private async ValueTask<bool> TryHandleProxy(MessageCreateEvent evt, Guild guild, Channel channel,
MessageContext ctx) MessageContext ctx)
{ {
if (ctx.IsDeleting) return false;
var botPermissions = await _cache.PermissionsIn(channel.Id); var botPermissions = await _cache.PermissionsIn(channel.Id);
try try

View File

@ -10,6 +10,11 @@ namespace PluralKit.Core;
public class MessageContext public class MessageContext
{ {
public SystemId? SystemId { get; } public SystemId? SystemId { get; }
/// <summary>
/// Whether a system is being deleted (no actions should be taken, or commands ran)
/// </summary>
public bool IsDeleting { get; }
public ulong? LogChannel { get; } public ulong? LogChannel { get; }
public bool InBlacklist { get; } public bool InBlacklist { get; }
public bool InLogBlacklist { get; } public bool InLogBlacklist { get; }

View File

@ -1,6 +1,7 @@
create function message_context(account_id bigint, guild_id bigint, channel_id bigint) create function message_context(account_id bigint, guild_id bigint, channel_id bigint)
returns table ( returns table (
system_id int, system_id int,
is_deleting bool,
log_channel bigint, log_channel bigint,
in_blacklist bool, in_blacklist bool,
in_log_blacklist bool, in_log_blacklist bool,
@ -27,6 +28,7 @@ as $$
guild as (select * from servers where id = guild_id) guild as (select * from servers where id = guild_id)
select select
system.id as system_id, system.id as system_id,
system.is_deleting,
guild.log_channel, guild.log_channel,
(channel_id = any(guild.blacklist)) as in_blacklist, (channel_id = any(guild.blacklist)) as in_blacklist,
(channel_id = any(guild.log_blacklist)) as in_log_blacklist, (channel_id = any(guild.log_blacklist)) as in_log_blacklist,

View File

@ -0,0 +1,5 @@
-- schema version 29
alter table systems add column is_deleting bool default false;
update info set schema_version = 29;

View File

@ -142,10 +142,11 @@ public partial class ModelRepository
}); });
} }
public Task DeleteSystem(SystemId id) public async Task DeleteSystem(SystemId id)
{ {
await _db.Execute(c => c.QueryAsync("update systems set is_deleting = true where id = @id", new { id = id }));
var query = new Query("systems").AsDelete().Where("id", id); var query = new Query("systems").AsDelete().Where("id", id);
await _db.ExecuteQuery(query);
_logger.Information("Deleted {SystemId}", id); _logger.Information("Deleted {SystemId}", id);
return _db.ExecuteQuery(query);
} }
} }

View File

@ -9,7 +9,7 @@ namespace PluralKit.Core;
internal class DatabaseMigrator internal class DatabaseMigrator
{ {
private const string RootPath = "PluralKit.Core.Database"; // "resource path" root for SQL files private const string RootPath = "PluralKit.Core.Database"; // "resource path" root for SQL files
private const int TargetSchemaVersion = 28; private const int TargetSchemaVersion = 29;
private readonly ILogger _logger; private readonly ILogger _logger;
public DatabaseMigrator(ILogger logger) public DatabaseMigrator(ILogger logger)