Skip to content

fix(teams): prevent concurrent slug collision with sequential retry (#499)#557

Open
Ridanshi wants to merge 4 commits into
Dev-Card:mainfrom
Ridanshi:fix/concurrent-team-slug-collision
Open

fix(teams): prevent concurrent slug collision with sequential retry (#499)#557
Ridanshi wants to merge 4 commits into
Dev-Card:mainfrom
Ridanshi:fix/concurrent-team-slug-collision

Conversation

@Ridanshi

Copy link
Copy Markdown
Contributor

Summary

  • Replace non-deterministic Math.random() suffix in generateUniqueSlug with sequential numeric candidates (my-teammy-team-1my-team-2, bounded at 10 attempts)
  • Wrap team creation in a 5-attempt retry loop that catches P2002 constraint violations and re-runs slug allocation instead of returning 409
  • Database @unique constraint on Team.slug is the authoritative guard; application layer now recovers when it fires under concurrent load

Root cause

generateUniqueSlug checked slug availability outside the transaction. Two concurrent requests could both observe the same slug as free, both enter $transaction, and the second would get a P2002 error that surfaced as an unrecoverable 409 — leaving one creation silently dead.

Concurrency strategy

Optimistic with bounded retry (Option A): rely on the existing DB unique constraint as the true arbiter, detect the collision via P2002, and retry slug generation with the next sequential candidate. No locks, no serializable isolation, no infinite loops.

Retry strategy

my-team → my-team-1 → my-team-2 → … → my-team-10
  • generateUniqueSlug: deterministic sequential suffixes, max 10 candidates, throws if all taken
  • Route handler: up to 5 full create attempts; returns 409 only after all retries exhausted

Files modified

  • apps/backend/src/utils/slug.ts — sequential suffix generation, bounded retries, typed signature
  • apps/backend/src/routes/team.ts — retry loop on P2002 in POST /, return type annotation, lint fixes
  • apps/backend/src/__tests__/team.test.ts — concurrency retry tests, exhaustion test, import/lint fixes
  • apps/backend/src/__tests__/slug.test.ts — new file: unit tests for createSlug and generateUniqueSlug

Schema changes

None — Team.slug @unique already existed in schema.prisma.

Tests added

  • slug.test.ts: 10 tests covering createSlug normalization and generateUniqueSlug determinism, suffix increment, bounds, concurrency
  • team.test.ts: retry-on-race-condition (201 after P2002 retry), retry-exhaustion (409 after 5 P2002s)

Validation

  • eslint src/utils/slug.ts src/routes/team.ts src/__tests__/team.test.ts src/__tests__/slug.test.ts0 errors
  • vitest run src/__tests__/slug.test.ts src/__tests__/team.test.ts57/57 pass

Fixes #499

Harxhit and others added 4 commits May 24, 2026 16:31
Signed-off-by: Prashantkumar Khatri <96608160+ShantKhatri@users.noreply.github.com>
Replace non-deterministic random suffix generation with sequential
numeric candidates (my-team → my-team-1 → my-team-2, capped at 10).
Wrap team creation in a bounded retry loop (5 attempts) so P2002
constraint violations from concurrent inserts trigger re-allocation
rather than surfacing as a 409. The database-level @unique constraint
on Team.slug remains the authoritative guard; application logic now
recovers gracefully when it fires.

Adds slug utility tests (createSlug, generateUniqueSlug determinism
and bounds) and team route tests for retry-on-race-condition and
retry-exhaustion paths.

Closes Dev-Card#499
@vercel

vercel Bot commented Jun 12, 2026

Copy link
Copy Markdown

@Ridanshi is attempting to deploy a commit to the Prashantkumar Khatri's projects Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions

Copy link
Copy Markdown

Hi @Ridanshi,

Thanks for opening this pull request.

This PR has been automatically classified based on the files modified.

Applied Labels

  • backend

Primary Review Area

  • backend

Reviewer

@Harxhit has been identified as the primary reviewer for this pull request.

If you have any questions regarding the affected area or implementation details, feel free to reach out to the assigned reviewer.

Thank you for your contribution!

@github-actions

Copy link
Copy Markdown

CI — All Checks Passed

Backend — SKIP

Check Result
Lint -
Test -
Typecheck -

Mobile — SKIP

Check Result
Lint -
Test -

Web — SKIP

Check Result
Check -
Build -

Last updated: Fri, 12 Jun 2026 13:43:07 GMT

@Harxhit Harxhit added the gssoc:approved Required label for every approved PR. Gives the base +50 points and enables contribution tracking. label Jun 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend gssoc:approved Required label for every approved PR. Gives the base +50 points and enables contribution tracking.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Concurrent team creation can generate duplicate slugs and cause team namespace collisions

3 participants