Add async discount processing with versioned cron jobs and soft delete#3967
Add async discount processing with versioned cron jobs and soft delete#3967devkiran wants to merge 3 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughMoves discount-related side effects out of DB transactions into queued cron workflows: adds Redis versioning, nullable Discount.programId, Zod job schema and Qstash publish, cron processors for batched enrollment updates and code deletions, orphaned-discounts cleanup, and updates actions to enqueue processing instead of performing in-transaction backfills. ChangesDiscount Async Processing System
🎯 3 (Moderate) | ⏱️ ~25 minutes
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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 |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
|
@coderabbitai review please |
|
✅ Actions performedReview triggered.
|
|
@coderabbitai full review please |
|
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
apps/web/lib/actions/partners/update-discount.ts (1)
69-78: 💤 Low valueOptional chaining may silently skip cache invalidation.
If
programis unexpectedlynull(e.g., due to a soft-deleted discount),revalidatePathwill receive paths like/partners.dub.co/undefined, which won't invalidate the intended cache. Consider guarding the entire block:...(partnerGroup?.slug === DEFAULT_PARTNER_GROUP.slug - ? [ + ? program + ? [ revalidatePath(`/partners.dub.co/${program?.slug}`), revalidatePath(`/partners.dub.co/${program?.slug}/apply`), program?.addedToMarketplaceAt && revalidatePath( `/partners.dub.co/programs/marketplace/${program.slug}`, ), ] + : [] : []),However, since
getDiscountOrThrowfilters byprogramId, a valid discount should always have a program. The optional chaining is acceptable as a defensive measure.🤖 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/actions/partners/update-discount.ts` around lines 69 - 78, The current cache-invalidation block uses optional chaining on program which can produce invalid paths like /partners.dub.co/undefined; update the conditional to guard that program is truthy before calling revalidatePath (e.g., check program && partnerGroup?.slug === DEFAULT_PARTNER_GROUP.slug) so revalidatePath is only invoked with valid program.slug and program.addedToMarketplaceAt; reference the partnerGroup, DEFAULT_PARTNER_GROUP, program, revalidatePath and getDiscountOrThrow symbols when locating and fixing the logic.
🤖 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/app/`(ee)/api/cron/discounts/process/route.ts:
- Around line 145-152: The catch block in the hard-delete logic is accessing
error.code on an unknown type; update the check to narrow the error to
Prisma.PrismaClientKnownRequestError (using a type guard like error instanceof
Prisma.PrismaClientKnownRequestError) before inspecting error.code === "P2025",
and keep the existing throw path that uses error instanceof Error ?
error.message : String(error) for the failure message; reference the catch block
around the hard-delete of discount (discount.id) and the imported Prisma symbol
to implement the type-safe check.
---
Nitpick comments:
In `@apps/web/lib/actions/partners/update-discount.ts`:
- Around line 69-78: The current cache-invalidation block uses optional chaining
on program which can produce invalid paths like /partners.dub.co/undefined;
update the conditional to guard that program is truthy before calling
revalidatePath (e.g., check program && partnerGroup?.slug ===
DEFAULT_PARTNER_GROUP.slug) so revalidatePath is only invoked with valid
program.slug and program.addedToMarketplaceAt; reference the partnerGroup,
DEFAULT_PARTNER_GROUP, program, revalidatePath and getDiscountOrThrow symbols
when locating and fixing the logic.
🪄 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
Run ID: 93a95aaf-5a38-45ad-a272-430ce2817213
📒 Files selected for processing (16)
apps/web/app/(ee)/api/admin/payouts/get-payouts-timeseries.tsapps/web/app/(ee)/api/cron/cleanup/orphaned-discounts/route.tsapps/web/app/(ee)/api/cron/discount-codes/create/queue-batches/route.tsapps/web/app/(ee)/api/cron/discount-codes/delete/queue/route.tsapps/web/app/(ee)/api/cron/discounts/process/route.tsapps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/webhooks/[webhookId]/page-client.tsxapps/web/app/providers.tsxapps/web/lib/actions/partners/create-discount.tsapps/web/lib/actions/partners/delete-discount.tsapps/web/lib/actions/partners/update-discount.tsapps/web/lib/api/discounts/discount-version.tsapps/web/lib/api/discounts/queue-discount-processing.tsapps/web/lib/discounts/create-discount-code.tsapps/web/playwright/workspaces/billing-trial.spec.tsapps/web/ui/partners/partner-link-selector.tsxpackages/prisma/schema/discount.prisma
Summary by CodeRabbit
New Features
Bug Fixes
Refactor