fix(discord): avoid duplicate schedule send after new session
This commit is contained in:
@@ -1,7 +1,6 @@
|
|||||||
using Dapper;
|
using Dapper;
|
||||||
using GmRelay.DiscordBot.Infrastructure.Discord;
|
using GmRelay.DiscordBot.Infrastructure.Discord;
|
||||||
using GmRelay.Shared.Domain;
|
using GmRelay.Shared.Domain;
|
||||||
using GmRelay.Shared.Platform;
|
|
||||||
using GmRelay.Shared.Rendering;
|
using GmRelay.Shared.Rendering;
|
||||||
using Npgsql;
|
using Npgsql;
|
||||||
|
|
||||||
@@ -12,7 +11,6 @@ public sealed record TimeParseResult(bool IsSuccess, DateTimeOffset Value, strin
|
|||||||
public sealed class DiscordNewSessionHandler(
|
public sealed class DiscordNewSessionHandler(
|
||||||
NpgsqlDataSource dataSource,
|
NpgsqlDataSource dataSource,
|
||||||
DiscordPermissionChecker permissionChecker,
|
DiscordPermissionChecker permissionChecker,
|
||||||
IPlatformMessenger messenger,
|
|
||||||
ILogger<DiscordNewSessionHandler> logger)
|
ILogger<DiscordNewSessionHandler> logger)
|
||||||
{
|
{
|
||||||
public static TimeParseResult ParseTimeInput(string input)
|
public static TimeParseResult ParseTimeInput(string input)
|
||||||
@@ -75,6 +73,7 @@ public sealed class DiscordNewSessionHandler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
await using var transaction = await connection.BeginTransactionAsync(cancellationToken);
|
await using var transaction = await connection.BeginTransactionAsync(cancellationToken);
|
||||||
|
var transactionCommitted = false;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await connection.ExecuteAsync(
|
await connection.ExecuteAsync(
|
||||||
@@ -125,23 +124,19 @@ public sealed class DiscordNewSessionHandler(
|
|||||||
transaction);
|
transaction);
|
||||||
|
|
||||||
await transaction.CommitAsync(cancellationToken);
|
await transaction.CommitAsync(cancellationToken);
|
||||||
|
transactionCommitted = true;
|
||||||
logger.LogInformation("Created session {SessionId} in guild {GuildId}", sessionId, guildId);
|
logger.LogInformation("Created session {SessionId} in guild {GuildId}", sessionId, guildId);
|
||||||
|
|
||||||
var sessions = new[] { new SessionBatchDto(sessionId, scheduledAt.UtcDateTime, SessionStatus.Planned, maxPlayers, joinLink ?? string.Empty) };
|
var sessions = new[] { new SessionBatchDto(sessionId, scheduledAt.UtcDateTime, SessionStatus.Planned, maxPlayers, joinLink ?? string.Empty) };
|
||||||
var view = SessionBatchViewBuilder.Build(title, sessions, Array.Empty<ParticipantBatchDto>());
|
return SessionBatchViewBuilder.Build(title, sessions, Array.Empty<ParticipantBatchDto>());
|
||||||
|
|
||||||
await messenger.SendScheduleAsync(
|
|
||||||
new PlatformScheduleMessage(
|
|
||||||
new PlatformGroup(PlatformKind.Discord, guildId, guildId, channelId),
|
|
||||||
view,
|
|
||||||
null),
|
|
||||||
cancellationToken);
|
|
||||||
|
|
||||||
return view;
|
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
await transaction.RollbackAsync(cancellationToken);
|
if (!transactionCommitted)
|
||||||
|
{
|
||||||
|
await transaction.RollbackAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -127,6 +127,18 @@ public sealed class DiscordNewSessionHandlerTests
|
|||||||
Assert.Contains("RollbackAsync", source, StringComparison.Ordinal);
|
Assert.Contains("RollbackAsync", source, StringComparison.Ordinal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Handler_ShouldNotRollbackCommittedTransactionAfterPostCommitFailure()
|
||||||
|
{
|
||||||
|
var repoRoot = GetRepoRoot();
|
||||||
|
var handlerPath = Path.Combine(repoRoot, "src", "GmRelay.DiscordBot", "Features", "Sessions", "DiscordNewSessionHandler.cs");
|
||||||
|
var source = File.ReadAllText(handlerPath);
|
||||||
|
|
||||||
|
Assert.Contains("transactionCommitted = false", source, StringComparison.Ordinal);
|
||||||
|
Assert.Contains("transactionCommitted = true", source, StringComparison.Ordinal);
|
||||||
|
Assert.Contains("if (!transactionCommitted)", source, StringComparison.Ordinal);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Handler_ShouldRespectCancellationToken()
|
public void Handler_ShouldRespectCancellationToken()
|
||||||
{
|
{
|
||||||
@@ -148,6 +160,17 @@ public sealed class DiscordNewSessionHandlerTests
|
|||||||
Assert.Contains("message.Embeds = embeds", source, StringComparison.Ordinal);
|
Assert.Contains("message.Embeds = embeds", source, StringComparison.Ordinal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Handler_ShouldLeaveScheduleMessageCreationToInteractionResponse()
|
||||||
|
{
|
||||||
|
var repoRoot = GetRepoRoot();
|
||||||
|
var handlerPath = Path.Combine(repoRoot, "src", "GmRelay.DiscordBot", "Features", "Sessions", "DiscordNewSessionHandler.cs");
|
||||||
|
var source = File.ReadAllText(handlerPath);
|
||||||
|
|
||||||
|
Assert.DoesNotContain("SendScheduleAsync", source, StringComparison.Ordinal);
|
||||||
|
Assert.DoesNotContain("PlatformScheduleMessage", source, StringComparison.Ordinal);
|
||||||
|
}
|
||||||
|
|
||||||
private static DateTimeOffset FutureDateAt1930()
|
private static DateTimeOffset FutureDateAt1930()
|
||||||
{
|
{
|
||||||
var future = DateTimeOffset.UtcNow.AddDays(7);
|
var future = DateTimeOffset.UtcNow.AddDays(7);
|
||||||
|
|||||||
Reference in New Issue
Block a user