Skip to content

fix(polls): race condition problems issues #1995

Merged
nikkothari22 merged 11 commits into
developfrom
1908-bug-race-condition-where-simultaneous-vote-requests-to-a-poll-are-all-accepted
Jan 18, 2026
Merged

fix(polls): race condition problems issues #1995
nikkothari22 merged 11 commits into
developfrom
1908-bug-race-condition-where-simultaneous-vote-requests-to-a-poll-are-all-accepted

Conversation

@prathameshkurunkar7

Copy link
Copy Markdown
Member

Fix Polls Race Condition: Prevent Duplicate Votes

Problem

Users could cast multiple votes in single-select polls due to race condition issue:

Issue #1: Same Option Multiple Times by same user on same poll

User clicks same option rapidly → Multiple vote records created for identical choice
This issue can be seen in #1908

User A | Poll: "Lunch?" | Option: "Yes" 
Database: 3 duplicate rows ❌

Issue #2: Multiple Options in Single-Select Poll by same user

User rapidly clicks different options → Both votes registered in single-select poll

User A | Poll: "Approve?" (single-select)
Database: "Yes" ✓ and "No" ✓ (both recorded!) ❌

Root Cause: No database-level uniqueness enforcement. Application checks and inserts were separate operations, allowing concurrent requests to slip through.


Solution

Restructured from flat table to parent-child model with UNIQUE(poll_id, user_id) constraint.

Before (Flat Structure)

Raven Poll Vote: poll_id, user_id, option
→ Multiple rows per user possible ❌

After (Parent-Child Structure)

Raven Poll Vote: poll_id, user_id
  UNIQUE(poll_id, user_id) ✓
  └── Raven Poll Vote Selection (child): option

Database enforces: One vote per user per poll. Race conditions now fail at DB level.


Changes

Backend

  1. New DocType: Raven Poll Vote Selection (child table for selected options)
  2. Updated APIs: add_vote(), get_poll(), get_all_votes() - same structure - different operations internally
  3. Updated DocType: Validations in before_insert(), counting from child table in update_poll_votes()
  4. Unique Constraint: UNIQUE(poll_id, user_id) on Raven Poll Vote

Migration

  1. Cleanup Patch: Removes existing duplicates (keeps oldest for same option, last modified for different options)
  2. Migration Patch: Moves option data to child table Raven Poll Vote Selection
  3. Constraint Patch: Adds unique constraint after cleanup
  4. In "on_doctype_update" added check frappe.flags.in_install to only apply the unique constraint directly on fresh site install. Else it would be applied via patch.

Testing

Verified results on latest backup of prod.


parent?: string
parentfield?: string
parenttype?: string
idx?: number

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@prathameshkurunkar7 Looks like frappe-types isn't adding option here right? The doctype has the field though. So weird.

@nikkothari22 nikkothari22 merged commit e40c026 into develop Jan 18, 2026
2 checks passed
@nikkothari22 nikkothari22 deleted the 1908-bug-race-condition-where-simultaneous-vote-requests-to-a-poll-are-all-accepted branch January 18, 2026 17:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants