Skip to content

Prevent race during school creation per creator - #972

Open
cocomarine wants to merge 9 commits into
mainfrom
1612-fix-race-when-creating-schools
Open

Prevent race during school creation per creator#972
cocomarine wants to merge 9 commits into
mainfrom
1612-fix-race-when-creating-schools

Conversation

@cocomarine

@cocomarine cocomarine commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Status

What's changed?

Race fix during school creation

  • Take a Postgres transaction-scoped advisory lock keyed on creator_id before save!.
    • Two concurrent creates by the same creator are now serialised: the loser blocks until the winner commits, so its uniqueness validation sees the winner's school instead of blowing up on the partial unique index on creator_id.
  • Rescue ActiveRecord::RecordInvalid separately and only report to Sentry when the failure isn't creator_id: :taken
    • a double submit is expected user behaviour, not an error worth alerting on.
  • Made failure/logging null-safe so an error raised before the school is built can't itself raise a NoMethodError.
  • Specs cover the lock being acquired, and the "creator already has a school" path: no second school, failed response, validation error (not a DB uniqueness violation), no onboarding call, no Sentry capture.

@cla-bot cla-bot Bot added the cla-signed label Aug 18, 2026
@github-actions

github-actions Bot commented Aug 18, 2026

Copy link
Copy Markdown

Test coverage

93.35% line coverage reported by SimpleCov.
Run: https://github.com/RaspberryPiFoundation/editor-api/actions/runs/32358418419

@cocomarine
cocomarine temporarily deployed to editor-api-p-1612-fix-r-avlkgw August 18, 2026 16:17 Inactive
Comment thread lib/concepts/school/operations/create.rb Fixed
@cocomarine
cocomarine temporarily deployed to editor-api-p-1612-fix-r-avlkgw August 20, 2026 07:21 Inactive
@cocomarine
cocomarine temporarily deployed to editor-api-p-1612-fix-r-avlkgw August 20, 2026 07:55 Inactive
rescue ActiveRecord::RecordInvalid => e
# A double submit loses the advisory lock race and fails the creator_id
# uniqueness validation as expected, so keep it out of Sentry.
Sentry.capture_exception(e) unless response[:school]&.errors&.of_kind?(:creator_id, :taken)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

addressed

@cocomarine
cocomarine temporarily deployed to editor-api-p-1612-fix-r-avlkgw August 20, 2026 07:59 Inactive
@cocomarine
cocomarine temporarily deployed to editor-api-p-1612-fix-r-avlkgw August 20, 2026 08:15 Inactive
@cocomarine
cocomarine marked this pull request as ready for review August 20, 2026 08:26
Copilot AI lite review requested due to automatic review settings August 20, 2026 08:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses a concurrency race in School::Create where two near-simultaneous school-creation requests from the same creator could bypass the model validation and fail at the database unique index. It introduces a transaction-scoped Postgres advisory lock keyed on creator_id, adjusts error/Sentry handling for expected double-submits, and adds specs to cover the new behavior.

Changes:

  • Acquire a transaction-scoped advisory lock (per creator_id) before save! to serialize concurrent creates.
  • Refine rescue behavior to avoid Sentry noise for expected creator_id: :taken validation failures and make logging/error construction nil-safe.
  • Add specs asserting the advisory lock call and the “creator already has a school” failure path (no second school, no onboarding, no Sentry capture).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
lib/concepts/school/operations/create.rb Adds advisory-lock serialization and refines error/logging/Sentry handling for expected validation failures.
spec/concepts/school/create_spec.rb Adds coverage for lock acquisition and the expected “creator already has a school” failure behavior.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread lib/concepts/school/operations/create.rb
@zetter-rpf

zetter-rpf commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Do you know if it's easy it is to double submit this form on the frontend (e.g. by clicking the button twice or hitting return in the form multiple times)? If it is, we might be able to avoid the user seeing an error at all by disabling the form while it's submitting.

This approach is good for stopping the error, but if we can prevent the user getting into this state in the first place it's a better experience for them and might mean this isn't needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants