signup: close two concurrency holes from final review
(1) RegisterAnonymousViewer now catches the unique-violation
race (SQLSTATE 23505 on Postgres / code 19 on SQLite) and
re-reads by UDID, returning the existing row instead of
surfacing 500 to the second concurrent /tool/signup caller.
New repo test exercises the back-to-back register path.
(2) Add unique index on SocialAccountConnection (AccountType,
AccountId). The auth handler's find-or-link path claimed
this index existed as the dedup backstop; the claim was
accurate as design intent but the schema was missing. Now
matched. Comment in handler updated.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -99,8 +99,11 @@ public class SteamSessionAuthenticationHandler : AuthenticationHandler<SteamAuth
|
||||
{
|
||||
// Find-or-link: first authenticated request after /tool/signup. The client signed up
|
||||
// anonymously and has no Steam social row yet; if the UDID resolves to a viewer, attach
|
||||
// Steam to it now so subsequent requests hit the fast SteamId path. The SteamId unique
|
||||
// index on SocialAccountConnection is the dedup backstop for concurrent first-touch.
|
||||
// Steam to it now so subsequent requests hit the fast SteamId path. The unique index
|
||||
// on SocialAccountConnection (AccountType, AccountId) — declared in OnModelCreating —
|
||||
// is the second-layer dedup backstop: if two concurrent first-touches both pass the
|
||||
// .Any(...) check in LinkSteamToViewer, the second SaveChanges throws cleanly instead
|
||||
// of silently duplicating connections.
|
||||
Guid? udid = Context.GetUdid();
|
||||
if (udid is Guid u && u != Guid.Empty)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user