fix(shared): filter due proposals by source_platform to prevent cross-platform race
PR Checks / test-and-build (pull_request) Successful in 6m11s

Both Telegram and Discord deadline services were querying ALL due
proposals without filtering by source_platform. If the Telegram
service reached a Discord proposal first, it finalized the DB state
but skipped message handling. The Discord service then saw status
!= 'Voting' and never updated the Discord vote message.

Fix: GetDueProposalIdsAsync now accepts a sourcePlatform parameter
and filters at the DB level. Each service only processes its own
platform's proposals.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-20 12:48:25 +03:00
parent 35548a03cb
commit db9a931ed6
3 changed files with 5 additions and 4 deletions
@@ -46,7 +46,7 @@ public sealed class RescheduleVotingDeadlineService(
{
try
{
var proposalIds = await finalizer.GetDueProposalIdsAsync(ct);
var proposalIds = await finalizer.GetDueProposalIdsAsync("Telegram", ct);
foreach (var proposalId in proposalIds)
{
@@ -34,7 +34,7 @@ public sealed class DiscordRescheduleVotingDeadlineService(
{
try
{
var proposalIds = await finalizer.GetDueProposalIdsAsync(ct);
var proposalIds = await finalizer.GetDueProposalIdsAsync("Discord", ct);
foreach (var id in proposalIds)
{
await TryFinalizeAsync(id, ct);
@@ -26,7 +26,7 @@ public sealed class RescheduleVotingFinalizer(
ISystemClock clock,
ILogger<RescheduleVotingFinalizer> logger)
{
public async Task<IReadOnlyList<Guid>> GetDueProposalIdsAsync(CancellationToken ct)
public async Task<IReadOnlyList<Guid>> GetDueProposalIdsAsync(string sourcePlatform, CancellationToken ct)
{
await using var connection = await dataSource.OpenConnectionAsync(ct);
var proposalIds = (await connection.QueryAsync<Guid>(
@@ -36,10 +36,11 @@ public sealed class RescheduleVotingFinalizer(
WHERE status = 'Voting'
AND voting_deadline_at IS NOT NULL
AND voting_deadline_at <= @Now
AND source_platform = @SourcePlatform
ORDER BY voting_deadline_at
LIMIT 25
""",
new { Now = clock.UtcNow.UtcDateTime })).ToList();
new { Now = clock.UtcNow.UtcDateTime, SourcePlatform = sourcePlatform })).ToList();
return proposalIds;
}