fix: prevent race on duplicate respondent insert#1445
fix: prevent race on duplicate respondent insert#1445Eraxyso wants to merge 5 commits intofix/openapifrom
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This reverts commit 6c3e32b.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## fix/openapi #1445 +/- ##
===============================================
- Coverage 66.17% 66.12% -0.06%
===============================================
Files 25 25
Lines 3598 3604 +6
===============================================
+ Hits 2381 2383 +2
- Misses 852 857 +5
+ Partials 365 364 -1 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
revertしているから何にも入ってないかも |
|
ごめん、これはまだいい回避方法見つかってないです |
|
@copilot I didn't find a good way to solve this problem simply, can you give some suggestions? |
I’ve added a SELECT … FOR UPDATE lock when checking existing respondents so concurrent inserts for questionnaires that disallow duplicates serialize and the second attempt receives ErrDuplicatedAnswered instead of slipping through (3ae6106). |
There was a problem hiding this comment.
Pull request overview
This PR aims to prevent concurrent duplicate inserts of respondents for questionnaires that disallow duplicate answers by adding a locking read during the “already answered?” check.
Changes:
- Add
gorm.io/gorm/clauseimport. - Apply
SELECT ... FOR UPDATE(viaclause.Locking{Strength: "UPDATE"}) to the duplicate-respondent existence check inInsertRespondent.
Comments suppressed due to low confidence (1)
model/respondents_impl.go:108
- This change introduces concurrency-sensitive behavior (duplicate-respondent prevention via locking), but there are no tests asserting
ErrDuplicatedAnsweredbehavior for non-duplicate questionnaires, nor any concurrency test that runs two transactions in parallel. Adding at least a regression test that two inserts by the same user into a non-duplicate-allowed questionnaire results inErrDuplicatedAnswered(and ideally a concurrent version using two goroutines + transactions) would help prevent future regressions.
if !questionnaire.IsDuplicateAnswerAllowed {
err = db.
Clauses(clause.Locking{Strength: "UPDATE"}).
Where("questionnaire_id = ? AND user_traqid = ?", questionnaireID, userID).
First(&Respondents{}).Error
if err == nil {
return 0, ErrDuplicatedAnswered
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| err = db. | ||
| Clauses(clause.Locking{Strength: "UPDATE"}). | ||
| Where("questionnaire_id = ? AND user_traqid = ?", questionnaireID, userID). | ||
| First(&Respondents{}).Error |
There was a problem hiding this comment.
SELECT ... FOR UPDATE here may not reliably provide the intended per-(questionnaire_id,user_traqid) serialization because the respondents table has no index/unique constraint on these columns (see Respondents struct), so this query will degenerate into a full table scan and can lock far more than intended (or behave DB/optimizer-dependent when no row exists). Consider instead locking a stable row that always exists (e.g., questionnaires row WHERE id = ? FOR UPDATE) before checking/inserting, and/or add a composite index (and preferably a uniqueness constraint if semantics allow) on (questionnaire_id, user_traqid) so the lock is scoped and deterministic.
… questionnaire row
3ae6106 to
cfd403c
Compare
|
from Claude code: The check-then-insert is not atomic. Between the check and the insert, another transaction can sneak in. Now the sequence becomes: This correctly serializes all concurrent InsertRespondent calls per-questionnaire. |
Adds row-level locking when checking for existing respondents on questionnaires that disallow duplicate answers, preventing concurrent inserts from bypassing the single-response restriction.
Changes Made
SELECT … FOR UPDATElock during duplicate-respondent check to serialize concurrent inserts.ErrDuplicatedAnsweredfor the second concurrent attempt instead of allowing multiple rows.Testing
⌨️ Start Copilot coding agent tasks without leaving your editor — available in VS Code, Visual Studio, JetBrains IDEs and Eclipse.