review(bp): move SaveChanges into repo with race protection; JST constant

GetOrCreateProgressAsync now persists the new row itself and catches
DbUpdateException on unique-constraint violations — concurrent /info
calls no longer throw 500s. BattlePassService no longer calls
SaveChangesAsync after the get-or-create. FormatWireDate uses a named
JstOffset constant instead of an inline TimeSpan.FromHours(9).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-05-26 23:22:48 -04:00
parent 8a35f8c40b
commit d877febcb8
2 changed files with 16 additions and 4 deletions

View File

@@ -26,7 +26,18 @@ public sealed class ViewerBattlePassRepository : IViewerBattlePassRepository
WeeklyPeriodStart = null,
};
_db.ViewerBattlePassProgress.Add(entry);
return entry;
try
{
await _db.SaveChangesAsync(ct);
return entry;
}
catch (DbUpdateException)
{
// Concurrent /info call won the race; re-read the row the other thread persisted.
_db.Entry(entry).State = EntityState.Detached;
return await _db.ViewerBattlePassProgress
.FirstAsync(p => p.ViewerId == viewerId && p.SeasonId == seasonId, ct);
}
}
public Task<List<ViewerBattlePassClaimEntry>> GetClaimsAsync(long viewerId, int seasonId, CancellationToken ct) =>