Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@devkiran
Copy link
Collaborator

@devkiran devkiran commented Dec 17, 2025

Summary by CodeRabbit

  • Chores
    • Refactored internal cron job infrastructure to use a standardized request handling wrapper, improving error logging and control flow consistency across partner management endpoints.

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link
Contributor

vercel bot commented Dec 17, 2025

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

Project Deployment Review Updated (UTC)
dub Ready Ready Preview Dec 19, 2025 10:30am

@devkiran devkiran requested a review from steven-tey December 17, 2025 12:08
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 17, 2025

Walkthrough

Two cron route handlers (auto-approve-partner and ban/process) are refactored to use the withCron wrapper, replacing direct POST handlers with wrapped async functions that parse from rawBody. The withCron utility is updated to use Axiom logger for error handling and to reject unsupported HTTP methods.

Changes

Cohort / File(s) Summary
Cron route refactoring
apps/web/app/(ee)/api/cron/auto-approve-partner/route.ts, apps/web/app/(ee)/api/cron/partners/ban/process/route.ts
Both handlers wrapped with withCron; POST signature changed from async function POST(req: Request) to const POST = withCron(async ({ rawBody }) => ...). Request parsing moved to rawBody parameter. Error handling and Qstash verification delegated to withCron. Logic flow reorganized: early validation guards, followed by conditional operations (fraud checks, email sends, database transactions).
Cron utility enhancement
apps/web/lib/cron/with-cron.ts
Error handling replaced with Axiom logger for structured logging; logger flushes on error. Added explicit else clause to throw on unsupported HTTP methods. Error response standardized via logAndRespond with 500 status.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

  • Verify that withCron wrapper correctly parses rawBody and maintains error boundaries for both endpoints
  • Confirm logic flow integrity in auto-approve-partner (fraud risk checks and early validation guards)
  • Check ban endpoint email notification logic within try/catch and partner cross-program fraud event creation
  • Validate Axiom logger integration in with-cron.ts and error response formatting

Possibly related PRs

  • PR #3207: Applies the same withCron wrapper pattern to other cron routes and modifies the with-cron.ts utility in parallel.

Suggested reviewers

  • steven-tey

Poem

🐰 Wrapped in cron, the routes now flow,
Where rawBody learns to glow,
Axiom logs each step with care,
Bans and approvals, swift and fair!

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Refactor cron routes to use withCron middleware' directly and clearly describes the main change across all modified files—migrating cron route handlers to use the withCron wrapper utility.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch axiom-cron-jobs

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 and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
apps/web/app/(ee)/api/cron/partners/ban/process/route.ts (1)

172-193: Empty catch block silently swallows email errors.

While it's correct that email failures shouldn't fail the ban process, silently swallowing errors loses observability. Consider logging the error:

-    } catch {}
+    } catch (error) {
+      console.error(`Failed to send ban notification email to ${partner.email}:`, error);
+    }

Also, the non-null assertion on line 189 (bannedReason!) is redundant since the ternary already handles the null case.

-          bannedReason: programEnrollment.bannedReason
-            ? BAN_PARTNER_REASONS[programEnrollment.bannedReason!]
-            : "",
+          bannedReason: programEnrollment.bannedReason
+            ? BAN_PARTNER_REASONS[programEnrollment.bannedReason]
+            : "",
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7a6aedb and 8417a80.

📒 Files selected for processing (3)
  • apps/web/app/(ee)/api/cron/auto-approve-partner/route.ts (2 hunks)
  • apps/web/app/(ee)/api/cron/partners/ban/process/route.ts (2 hunks)
  • apps/web/lib/cron/with-cron.ts (3 hunks)
🧰 Additional context used
🧠 Learnings (7)
📓 Common learnings
Learnt from: devkiran
Repo: dubinc/dub PR: 3207
File: apps/web/lib/cron/with-cron.ts:27-56
Timestamp: 2025-12-09T12:54:41.818Z
Learning: In `apps/web/lib/cron/with-cron.ts`, the `withCron` wrapper extracts the request body once and provides it to handlers via the `rawBody` parameter. Handlers should use this `rawBody` string parameter (e.g., `JSON.parse(rawBody)`) rather than reading from the Request object via `req.json()` or `req.text()`.
Learnt from: devkiran
Repo: dubinc/dub PR: 3213
File: apps/web/app/(ee)/api/cron/auto-approve-partner/route.ts:122-122
Timestamp: 2025-12-15T16:45:51.667Z
Learning: In the Dub codebase, cron endpoints under apps/web/app/(ee)/api/cron/ use handleCronErrorResponse for error handling, which intentionally does NOT detect QStash callbacks or set Upstash-NonRetryable-Error headers. This allows QStash to retry all cron job errors using its native retry mechanism. The selective retry logic (queueFailedRequestForRetry) is only used for specific user-facing API endpoints like /api/track/lead, /api/track/sale, and /api/links to retry only transient Prisma database errors.
📚 Learning: 2025-12-09T12:54:41.818Z
Learnt from: devkiran
Repo: dubinc/dub PR: 3207
File: apps/web/lib/cron/with-cron.ts:27-56
Timestamp: 2025-12-09T12:54:41.818Z
Learning: In `apps/web/lib/cron/with-cron.ts`, the `withCron` wrapper extracts the request body once and provides it to handlers via the `rawBody` parameter. Handlers should use this `rawBody` string parameter (e.g., `JSON.parse(rawBody)`) rather than reading from the Request object via `req.json()` or `req.text()`.

Applied to files:

  • apps/web/lib/cron/with-cron.ts
  • apps/web/app/(ee)/api/cron/auto-approve-partner/route.ts
  • apps/web/app/(ee)/api/cron/partners/ban/process/route.ts
📚 Learning: 2025-12-03T09:19:48.164Z
Learnt from: devkiran
Repo: dubinc/dub PR: 3175
File: apps/web/lib/actions/partners/bulk-reject-partner-applications.ts:14-21
Timestamp: 2025-12-03T09:19:48.164Z
Learning: In apps/web/lib/actions/partners/bulk-reject-partner-applications.ts, the bulkRejectPartnerApplicationsAction does not need explicit plan capability checks for fraud operations (when reportFraud is true) because the authorization is handled automatically by the underlying fraud operation functions (resolveFraudGroups, createFraudEvents) or through other automated mechanisms in the system.

Applied to files:

  • apps/web/app/(ee)/api/cron/auto-approve-partner/route.ts
  • apps/web/app/(ee)/api/cron/partners/ban/process/route.ts
📚 Learning: 2025-12-15T16:45:51.667Z
Learnt from: devkiran
Repo: dubinc/dub PR: 3213
File: apps/web/app/(ee)/api/cron/auto-approve-partner/route.ts:122-122
Timestamp: 2025-12-15T16:45:51.667Z
Learning: In cron endpoints under apps/web/app/(ee)/api/cron, continue using handleCronErrorResponse for error handling. Do not detect QStash callbacks or set Upstash-NonRetryable-Error headers in these cron routes, so QStash can retry cron errors via its native retry mechanism. The existing queueFailedRequestForRetry logic should remain limited to specific user-facing API endpoints (e.g., /api/track/lead, /api/track/sale, /api/links) to retry only transient Prisma/database errors. This pattern should apply to all cron endpoints under the cron directory in this codebase.

Applied to files:

  • apps/web/app/(ee)/api/cron/auto-approve-partner/route.ts
  • apps/web/app/(ee)/api/cron/partners/ban/process/route.ts
📚 Learning: 2025-11-24T09:10:12.536Z
Learnt from: devkiran
Repo: dubinc/dub PR: 3089
File: apps/web/lib/api/fraud/fraud-rules-registry.ts:17-25
Timestamp: 2025-11-24T09:10:12.536Z
Learning: In apps/web/lib/api/fraud/fraud-rules-registry.ts, the fraud rules `partnerCrossProgramBan` and `partnerDuplicatePayoutMethod` intentionally have stub implementations that return `{ triggered: false }` because they are partner-scoped rules handled separately during partner application/onboarding flows (e.g., in detect-record-fraud-application.ts), rather than being evaluated per conversion event like other rules in the registry. The stubs exist only to satisfy the `Record<FraudRuleType, ...>` type constraint.

Applied to files:

  • apps/web/app/(ee)/api/cron/auto-approve-partner/route.ts
  • apps/web/app/(ee)/api/cron/partners/ban/process/route.ts
📚 Learning: 2025-11-12T22:23:10.414Z
Learnt from: TWilson023
Repo: dubinc/dub PR: 3098
File: apps/web/lib/actions/partners/message-program.ts:49-58
Timestamp: 2025-11-12T22:23:10.414Z
Learning: In apps/web/lib/actions/partners/message-program.ts, when checking if a partner can continue messaging after messaging is disabled, the code intentionally requires `senderPartnerId: null` (program-initiated messages) to prevent partners from continuing to send junk messages. Only conversations started by the program should continue after messaging is disabled, as a spam prevention mechanism.

Applied to files:

  • apps/web/app/(ee)/api/cron/partners/ban/process/route.ts
📚 Learning: 2025-12-08T09:44:28.429Z
Learnt from: devkiran
Repo: dubinc/dub PR: 3200
File: apps/web/lib/api/fraud/detect-duplicate-payout-method-fraud.ts:55-73
Timestamp: 2025-12-08T09:44:28.429Z
Learning: In apps/web/lib/api/fraud/detect-duplicate-payout-method-fraud.ts, the fraud event creation logic intentionally generates self-referential fraud events (where partnerId equals duplicatePartnerId) for partners with duplicate payout methods. This is by design to create raw events for all partners involved in a duplicate payout method scenario, regardless of whether they reference themselves.

Applied to files:

  • apps/web/app/(ee)/api/cron/partners/ban/process/route.ts
🧬 Code graph analysis (3)
apps/web/lib/cron/with-cron.ts (2)
apps/web/lib/cron/verify-vercel.ts (1)
  • verifyVercelSignature (3-20)
apps/web/lib/axiom/server.ts (1)
  • logger (29-39)
apps/web/app/(ee)/api/cron/auto-approve-partner/route.ts (4)
apps/web/lib/cron/with-cron.ts (1)
  • withCron (21-75)
packages/prisma/index.ts (1)
  • prisma (3-9)
apps/web/lib/plan-capabilities.ts (1)
  • getPlanCapabilities (4-22)
apps/web/lib/api/fraud/get-partner-application-risks.ts (1)
  • getPartnerApplicationRisks (11-68)
apps/web/app/(ee)/api/cron/partners/ban/process/route.ts (6)
apps/web/lib/cron/with-cron.ts (1)
  • withCron (21-75)
apps/web/lib/api/programs/get-program-enrollment-or-throw.ts (1)
  • getProgramEnrollmentOrThrow (6-67)
apps/web/app/(ee)/api/cron/partners/ban/process/cancel-commissions.ts (1)
  • cancelCommissions (4-71)
apps/web/lib/api/partners/sync-total-commissions.ts (1)
  • syncTotalCommissions (5-50)
apps/web/lib/tinybird/record-link.ts (1)
  • recordLink (75-86)
apps/web/lib/api/fraud/create-fraud-events.ts (1)
  • createFraudEvents (13-160)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (9)
apps/web/lib/cron/with-cron.ts (2)

39-48: LGTM!

The explicit else-if structure with a catch-all throw for unsupported HTTP methods is clean and provides clear error messaging. The thrown error will be properly caught and logged by the surrounding try/catch block.


56-72: LGTM!

The error handling properly:

  1. Logs to console for immediate debugging
  2. Sends to Axiom for observability (with flush to ensure delivery)
  3. Uses the existing log utility for cron-type logging
  4. Returns a 500 status, allowing QStash to retry failed cron jobs per the established pattern

Based on learnings, this approach correctly allows QStash native retry mechanisms.

apps/web/app/(ee)/api/cron/auto-approve-partner/route.ts (3)

18-19: LGTM!

Correctly uses the rawBody parameter from withCron and parses it with JSON.parse() as per the established pattern in this codebase. This avoids the issue of reading the request body multiple times.

Based on learnings, this is the correct approach for withCron handlers.


52-76: LGTM!

The guard clauses handle expected skip conditions (missing enrollment, no group, auto-approval disabled, non-pending status) with descriptive log messages. Using logAndRespond without a 500 status prevents unnecessary QStash retries for these valid skip scenarios.


78-93: LGTM!

The fraud risk evaluation is correctly gated behind the canManageFraudEvents plan capability check, and high-risk partners are appropriately skipped rather than auto-approved, allowing for manual review.

apps/web/app/(ee)/api/cron/partners/ban/process/route.ts (4)

24-25: LGTM!

Correctly uses the withCron wrapper and parses rawBody with JSON.parse() as per the established pattern. Based on learnings, this is the correct approach.


55-106: LGTM!

The transaction correctly groups related ban operations atomically:

  • Links are disabled immediately via disabledAt and expiresAt
  • Only non-approved bounty submissions are rejected (preserving approved ones)
  • Discount codes are unlinked (with actual deletion queued separately)
  • Only pending payouts are canceled

The logging of counts after the transaction provides useful observability.


114-133: LGTM!

The parallel execution of independent cleanup tasks is efficient:

  • Commission sync updates totals after cancellation
  • Link cache expiration ensures stale data isn't served
  • Tinybird metadata is updated with deletion markers
  • Discount code deletion is properly queued

The filter correctly handles links without discount codes.


135-157: LGTM!

Correctly creates partnerCrossProgramBan fraud events for other programs where the partner is enrolled and approved. This enables cross-program fraud detection as documented in the learnings about fraud rules.

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.

2 participants