Prevent duplicate users from concurrent TMC create-user requests - #1745
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
🚧 Files skipped from review as they are similar to previous changes (3)
📝 WalkthroughWalkthroughAdds a partial unique index for active users by ChangesDuplicate user race fix
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 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 |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
services/headless-lms/server/src/domain/authorization.rs (1)
963-973: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider narrowing the fallback to unique-violation errors.
Any insert error (not just a unique-constraint violation from the new index) triggers a re-fetch by
upstream_idbefore falling back toinsert_error. Functionally safe since the original error is preserved when re-fetch finds nothing, but for unrelated failures (e.g. connection issues) this adds an extra query on the failure path. Optionally match on the underlying DB error code (23505) to only retry on genuine unique-violation races.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@services/headless-lms/server/src/domain/authorization.rs` around lines 963 - 973, In the user insert fallback inside the authorization flow, the current retry path in the match on inserted retries a lookup for every insert failure, not just genuine unique-violation races. Narrow this logic in the user creation path around models::users::find_by_upstream_id and the insert_error handling so the re-fetch only happens when the underlying DB error indicates a unique constraint violation (for example code 23505), and let other errors return immediately without the extra query.services/headless-lms/migrations/20260703090000_add-unique-index-users-upstream-id.up.sql (1)
9-11: 🚀 Performance & Scalability | 🔵 TrivialUse a concurrent index build here.
CREATE UNIQUE INDEXwill blockuserswhile the index is built; if this needs to stay online, switch toCREATE UNIQUE INDEX CONCURRENTLYand add-- no-transactionto this migration.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@services/headless-lms/migrations/20260703090000_add-unique-index-users-upstream-id.up.sql` around lines 9 - 11, This migration builds a unique index on users.upstream_id in a blocking way, so update the migration to use a concurrent index build instead. Change the CREATE UNIQUE INDEX statement in the users_upstream_id_active_uniq_idx migration to CREATE UNIQUE INDEX CONCURRENTLY, and mark the migration as no-transaction so the database can build it online without locking users.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In
`@services/headless-lms/migrations/20260703090000_add-unique-index-users-upstream-id.up.sql`:
- Around line 9-11: This migration builds a unique index on users.upstream_id in
a blocking way, so update the migration to use a concurrent index build instead.
Change the CREATE UNIQUE INDEX statement in the
users_upstream_id_active_uniq_idx migration to CREATE UNIQUE INDEX CONCURRENTLY,
and mark the migration as no-transaction so the database can build it online
without locking users.
In `@services/headless-lms/server/src/domain/authorization.rs`:
- Around line 963-973: In the user insert fallback inside the authorization
flow, the current retry path in the match on inserted retries a lookup for every
insert failure, not just genuine unique-violation races. Narrow this logic in
the user creation path around models::users::find_by_upstream_id and the
insert_error handling so the re-fetch only happens when the underlying DB error
indicates a unique constraint violation (for example code 23505), and let other
errors return immediately without the extra query.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 03958a72-9701-4cad-889b-062bddbf6e1d
📒 Files selected for processing (3)
services/headless-lms/migrations/20260703090000_add-unique-index-users-upstream-id.down.sqlservices/headless-lms/migrations/20260703090000_add-unique-index-users-upstream-id.up.sqlservices/headless-lms/server/src/domain/authorization.rs
find-then-insert in get_or_create_user_from_tmc_mooc_fi_response races when two requests arrive for the same not-yet-created upstream_id (which the tmc-server login-migration PR makes likely — parallel basic-auth API requests); adds a partial unique index on active users.upstream_id and makes the loser of the race fetch and return the winner's row. Include the pre-merge caution prominently: if production already has duplicate active users with the same upstream_id, the migration fails and blocks deploy — the check query is in the migration file's comment.
see testmycode/tmc-server#595
Summary by CodeRabbit