Skip to content

🚨 Race condition in game with actual video #2502

@khushal-winner

Description

@khushal-winner
  • Describe the bug
    A race condition occurs when multiple users (or the same user with rapid clicks) trigger the "Start Game" action at nearly the same time. Because card dealing and the started_at timestamp update are not wrapped in a transaction — and there is no unique constraint on DealtCard — both requests pass the game.started_at == nil check and then both execute the full card-dealing loop. This results in every card from the deck being inserted twice.

    Observed behavior

  • Normal (single click): each player receives exactly 26 unique cards (correct for a 3-player game)

  • Race condition triggered (two near-simultaneous "Start Game" clicks): each player receives 52 cards (the entire deck is dealt twice)

Before

2026-03-04.05-52-32.mp4

After (triggered the start game same time with mobile and laptop , mobile is not shown in the video because this is a screen recording)

2026-03-04.05-55-47.mp4

Expected behavior
Clicking "Start Game" should deal each card exactly once, mark the game as started (started_at set), and prevent any concurrent dealing process from duplicating cards.

Steps to reproduce
1. Create/join a game with >2 players
2. Ensure game is ready to start (both players present, deck loaded)
3. Have two browser tabs (or two users) click "Start Game" within ~100–300 ms of each other
4. Check the dealt cards — each player will have 52 cards instead of 26

Desktop environment
OS: Windows
Browser: Chrome
Version: 130+ (also reproducible in Edge/Firefox)

Additional context

  • Root cause: Repo.insert! calls in show.ex (lines ~77–84) run outside a transaction
  • No unique index exists on dealt_cards (card_id) or (card_id, player_id)
  • The started_at nil check is not atomic with the inserts
  • Fix suggestion: wrap both the card inserts and update_game call in Repo.transaction/1 (as previously shown)

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions