Skip to content

Fix race conditions in partner create-and-enroll upsert - #4237

Open
devkiran wants to merge 6 commits into
mainfrom
fix-partner-upsert
Open

Fix race conditions in partner create-and-enroll upsert#4237
devkiran wants to merge 6 commits into
mainfrom
fix-partner-upsert

Conversation

@devkiran

@devkiran devkiran commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • Bug Fixes
    • Improved partner and program enrollment reliability when multiple requests happen at the same time.
    • Prevented duplicate partner records and program enrollments under concurrency.
    • Added safer handling for existing enrollments, including clearer conflict behavior when tenant details don’t match.
  • Improvements
    • Reuses existing partners and enrollments automatically, preserving related links and platform information.
    • Partner enrollment flow now produces more consistent webhook triggering and usage updates.

@vercel

vercel Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
dub Ready Ready Preview Aug 6, 2026 4:25am

Request Review

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 820e82a5-18eb-4dca-a9b2-c348e3ab6c71

📥 Commits

Reviewing files that changed from the base of the PR and between fefcd09 and bbd8502.

📒 Files selected for processing (3)
  • apps/web/lib/api/partners/create-and-enroll-partner.ts
  • apps/web/lib/api/partners/create-or-get-program-enrollment.ts
  • apps/web/lib/api/partners/get-or-create-partner.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/web/lib/api/partners/get-or-create-partner.ts
  • apps/web/lib/api/partners/create-and-enroll-partner.ts
  • apps/web/lib/api/partners/create-or-get-program-enrollment.ts

📝 Walkthrough

Walkthrough

The partner enrollment flow now uses dedicated helpers to resolve partners and create or retrieve program enrollments, with existing-enrollment handling and downstream operations based on the returned enrollment data.

Changes

Partner enrollment flow

Layer / File(s) Summary
Partner resolution helper
apps/web/lib/api/partners/get-or-create-partner.ts
Partners are retrieved by email or created with generated usernames, with Prisma unique-conflict fallback handling.
Enrollment creation and conflict handling
apps/web/lib/api/partners/create-or-get-program-enrollment.ts
Program enrollments are created or retrieved by partner and program, including related data and tenant conflict validation.
Partner enrollment orchestration
apps/web/lib/api/partners/create-and-enroll-partner.ts
The enrollment flow uses the helpers and returned enrollment data for existing-enrollment responses, links, image storage, webhooks, and usage updates.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant createAndEnrollPartner
  participant getOrCreatePartner
  participant createOrGetProgramEnrollment
  participant Prisma
  createAndEnrollPartner->>getOrCreatePartner: resolve partner by email or create partner
  getOrCreatePartner->>Prisma: find or create Partner
  createAndEnrollPartner->>createOrGetProgramEnrollment: create or retrieve program enrollment
  createOrGetProgramEnrollment->>Prisma: create or find ProgramEnrollment
  createOrGetProgramEnrollment-->>createAndEnrollPartner: return enrollment and created flag
Loading

Possibly related PRs

  • dubinc/dub#3714: Refactors partner enrollment webhook payload construction so enrollment links are populated correctly.

Suggested reviewers: steven-tey, pepeladeira

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: reducing race conditions in the partner create-and-enroll flow.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-partner-upsert

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 5

🤖 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.

Inline comments:
In `@apps/web/lib/api/partners/create-and-enroll-partner.ts`:
- Around line 140-158: In the partner enrollment flow, change the concurrent
Promise.all around getGroupOrThrow and getOrCreatePartner so getGroupOrThrow
completes first and validates finalGroupId before any partner mutation begins.
Only invoke getOrCreatePartner after the group has been successfully retrieved,
while preserving the existing partner creation data and subsequent group usage.
- Around line 147-157: Extend getOrCreatePartner’s existing-partner conflict
path to update the submitted profile fields instead of only returning
findUniqueOrThrow’s stale record. Reuse the normalized values from the create
payload, including name, country, description, and image, so existing partners
are refreshed consistently with newly created ones.

In `@apps/web/lib/api/partners/create-or-get-program-enrollment.ts`:
- Around line 94-99: Update the existing-enrollment return branch in
createOrGetProgramEnrollment to compare programEnrollment.tenantId with the
requested tenantId before returning. Preserve the successful return for matching
tenants, but raise the same conflict or reconciliation error used by the
non-race path when they differ.

In `@apps/web/lib/api/partners/get-or-create-partner.ts`:
- Around line 27-38: Validate the result of generatePartnerUsername in the
get-or-create flow before calling prisma.partner.create. When it returns null
after exhausting retries, throw a clear, descriptive error and do not invoke
create; preserve the existing creation path for valid usernames.
- Around line 44-67: Update the P2002 handling in getOrCreatePartner to inspect
error.meta?.target and distinguish username conflicts from email conflicts. For
username collisions, retry the create flow with a newly generated username; only
use findUniqueOrThrow({ where: { email } }) when the unique constraint targets
email, preserving the existing return shape and error propagation for other
conflicts.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 117da1db-96c2-470c-b2cd-acdcbeea4c19

📥 Commits

Reviewing files that changed from the base of the PR and between fefcd09 and 6adbf6a.

📒 Files selected for processing (3)
  • apps/web/lib/api/partners/create-and-enroll-partner.ts
  • apps/web/lib/api/partners/create-or-get-program-enrollment.ts
  • apps/web/lib/api/partners/get-or-create-partner.ts

Comment thread apps/web/lib/api/partners/create-and-enroll-partner.ts Outdated
Comment thread apps/web/lib/api/partners/create-and-enroll-partner.ts Outdated
Comment thread apps/web/lib/api/partners/create-or-get-program-enrollment.ts Outdated
Comment thread apps/web/lib/api/partners/get-or-create-partner.ts
Comment thread apps/web/lib/api/partners/get-or-create-partner.ts
@devkiran
devkiran marked this pull request as ready for review July 29, 2026 16:09

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 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.

Inline comments:
In `@apps/web/lib/api/partners/create-or-get-program-enrollment.ts`:
- Around line 102-104: The conflict message in the enrollment error thrown by
create-or-get program enrollment incorrectly attributes the conflict to the
requested tenant. Update it to state that the same partner is already associated
with a different tenant in the program, using grammatically correct wording;
leave the conflict code and surrounding logic unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 1dd3b848-fcd9-4653-95a4-8b8e43f5cf16

📥 Commits

Reviewing files that changed from the base of the PR and between 6adbf6a and bbd8502.

📒 Files selected for processing (3)
  • apps/web/lib/api/partners/create-and-enroll-partner.ts
  • apps/web/lib/api/partners/create-or-get-program-enrollment.ts
  • apps/web/lib/api/partners/get-or-create-partner.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/web/lib/api/partners/get-or-create-partner.ts
  • apps/web/lib/api/partners/create-and-enroll-partner.ts

Comment on lines +102 to +104
throw new DubApiError({
message: `The tenantId '${tenantId}' is already in associated with another partner in this program.`,
code: "conflict",

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Correct the conflict message.

This lookup proves the same partner is already enrolled with a different tenant; it does not prove the requested tenant belongs to another partner. The current text is also grammatically malformed.

Proposed fix
- message: `The tenantId '${tenantId}' is already in associated with another partner in this program.`,
+ message: "This partner is already enrolled in this program with a different tenant ID.",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
throw new DubApiError({
message: `The tenantId '${tenantId}' is already in associated with another partner in this program.`,
code: "conflict",
throw new DubApiError({
message: "This partner is already enrolled in this program with a different tenant ID.",
code: "conflict",
🤖 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 `@apps/web/lib/api/partners/create-or-get-program-enrollment.ts` around lines
102 - 104, The conflict message in the enrollment error thrown by create-or-get
program enrollment incorrectly attributes the conflict to the requested tenant.
Update it to state that the same partner is already associated with a different
tenant in the program, using grammatically correct wording; leave the conflict
code and surrounding logic unchanged.

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.

1 participant