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

Skip to content

Conversation

@lucasfcosta
Copy link
Contributor

@lucasfcosta lucasfcosta commented Dec 8, 2025

This adds more detailed logging so we can time the execution of the different parts of the POST /api/cron/payouts/process/updates route.

This will help us determine which part of it is slow, and track how long the call to the Resend API is taking vs. the other operations and identify possible bottlenecks.

I couldn't find more detailed tracing libraries here so I defaulted to a pattern that seems to be used elsewhere that's simple enough for us to observe in the logs. Please let me know if I got it wrong and apologies in advance if I did.

Summary by CodeRabbit

  • Refactor

    • Payout processing now sends notification emails as a single batch for more reliable, efficient delivery.
  • Chores

    • Improved performance monitoring and logging around payout verification, data access, audit recording, and email delivery to aid monitoring and troubleshooting.

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

@vercel
Copy link
Contributor

vercel bot commented Dec 8, 2025

@lucasfcosta is attempting to deploy a commit to the Dub Team on Vercel.

A member of the Team first needs to authorize it.

@CLAassistant
Copy link

CLAassistant commented Dec 8, 2025

CLA assistant check
All committers have signed the CLA.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 8, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Adds timing instrumentation around QStash verification, the Prisma database query, audit log creation, and the Resend batch email API call; restructures email sends into a single batched request and logs consolidated per-step timings.

Changes

Cohort / File(s) Summary
Performance timing instrumentation
apps/web/app/(ee)/api/cron/payouts/process/updates/route.ts
Adds startTime, timings object, and time markers (t0t3); records durations for qstash verification, Prisma query, audit log, resendBatch API, and total processing; logs structured timings.
Email batching & control-flow adjustments
apps/web/app/(ee)/api/cron/payouts/process/updates/route.ts
Builds emailsToSend and issues a single batch email request instead of per-email sends; ensures timing captures occur around awaits and before early returns to preserve accurate measurements.

Sequence Diagram(s)

sequenceDiagram
  participant Q as QStash
  participant Server as RouteHandler
  participant DB as Prisma
  participant Audit as AuditLog
  participant Resend as ResendAPI

  Server->>Q: verify request (timing start t0)
  Q-->>Server: verification result (record qstashVerification)
  Server->>DB: query payouts/recipients (t1)
  DB-->>Server: query result (record prismaQuery)
  Server->>Audit: create audit log (t2)
  Audit-->>Server: audit saved (record auditLog)
  Server->>Resend: send batch emails (t3)
  Resend-->>Server: response (record resendBatchApi)
  Server->>Server: compute totalMs and log consolidated timings
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

  • Verify emailsToSend payload shape matches prior individual-send payloads (recipients, substitutions, metadata).
  • Confirm timing markers are placed around all awaited calls and before early returns.
  • Check structured logging keys and types for compatibility with observability pipelines.

Suggested reviewers

  • devkiran

Poem

🐇
I counted ticks — t0 to t3,
QStash, DB, Audit, Resend in a spree,
Emails bundled, hopped in one cart,
Timings told stories of each little part,
A rabbit nods — precise and smart! 🥕

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 'chore: add time logging to the payout processing route' directly and clearly describes the main change: adding timing instrumentation to log performance metrics in the payout processing route.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b93c5fc and 259ea0f.

📒 Files selected for processing (1)
  • apps/web/app/(ee)/api/cron/payouts/process/updates/route.ts (5 hunks)

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: 1

🧹 Nitpick comments (2)
apps/web/app/(ee)/api/cron/payouts/process/updates/route.ts (2)

64-68: Consider logging timings before early returns.

This early return bypasses the timing log at lines 133-150, losing qstashVerification and prismaQuery timing data. If you want comprehensive profiling, consider logging partial timings before returning.


152-166: Consider timing the qstash.publishJSON call.

For comprehensive bottleneck analysis, you may also want to time this external call to qstash when enqueuing the next batch.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 741404d and b93c5fc.

📒 Files selected for processing (1)
  • apps/web/app/(ee)/api/cron/payouts/process/updates/route.ts (4 hunks)
🔇 Additional comments (5)
apps/web/app/(ee)/api/cron/payouts/process/updates/route.ts (5)

24-25: LGTM - Clean timing instrumentation setup.

The use of performance.now() for high-resolution timing is appropriate for this use case.


30-35: LGTM.


41-62: LGTM.


133-150: LGTM - Well-structured timing output.

The structured JSON logging with consistent rounding and null handling for optional timings will be easy to parse and analyze.


104-110: The non-null assertions on partner.email are intentional and safe.

Lines 105 and 110 use ! on payout.partner.email as part of the established pattern in this codebase: sendBatchEmail filters out emails with invalid to addresses internally, making null checks at call sites unnecessary. This centralized validation approach is used throughout the payouts system.

The replyTo: payout.program.supportEmail || "noreply" fallback on line 108 may need review if "noreply" should be a fully qualified email address, but that's a separate concern from the non-null assertions.

@steven-tey
Copy link
Collaborator

@coderabbitai full review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 8, 2025

✅ Actions performed

Full review triggered.

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: 0

♻️ Duplicate comments (1)
apps/web/app/(ee)/api/cron/payouts/process/updates/route.ts (1)

104-129: Use undefined instead of invalid "noreply" reply‑to address

replyTo: payout.program.supportEmail || "noreply" introduces an invalid email address value. Unlike to, which the email layer centrally filters for invalid addresses (per repository learnings), replyTo may be forwarded as‑is to Resend/SMTP and cause validation errors.

A safer change is to omit replyTo when there is no support email, or use a guaranteed‑valid configured no‑reply address:

-        replyTo: payout.program.supportEmail || "noreply",
+        replyTo: payout.program.supportEmail || undefined,

(or wire this to a NO_REPLY_EMAIL env/config value that is a valid email).

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

24-150: Timing instrumentation is correct and side‑effect free

The new timing markers (startTime, t0–t3, timings, and the consolidated timings log) are well placed around the expensive async calls and don’t change route behavior. The numbers you log (per‑step + totalMs) should give a clear picture of where time is spent.

As an optional improvement, you could give timings an explicit shape instead of Record<string, number> to catch typos at compile time, e.g.:

const timings: {
  qstashVerification: number;
  prismaQuery: number;
  auditLog: number;
  resendBatchApi?: number;
} = { qstashVerification: 0, prismaQuery: 0, auditLog: 0 };
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 741404d and b93c5fc.

📒 Files selected for processing (1)
  • apps/web/app/(ee)/api/cron/payouts/process/updates/route.ts (4 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-11-17T05:19:11.972Z
Learnt from: devkiran
Repo: dubinc/dub PR: 3113
File: apps/web/app/(ee)/api/cron/payouts/charge-succeeded/send-paypal-payouts.ts:65-75
Timestamp: 2025-11-17T05:19:11.972Z
Learning: In the Dub codebase, `sendBatchEmail` (implemented in packages/email/src/send-via-resend.ts) handles filtering of emails with invalid `to` addresses internally. Call sites can safely use non-null assertions on email addresses because the email sending layer will filter out any entries with null/undefined `to` values before sending. This centralized validation pattern is intentional and removes the need for filtering at individual call sites.

Applied to files:

  • apps/web/app/(ee)/api/cron/payouts/process/updates/route.ts
🧬 Code graph analysis (1)
apps/web/app/(ee)/api/cron/payouts/process/updates/route.ts (3)
packages/utils/src/functions/currency-formatter.ts (1)
  • currencyFormatter (7-22)
packages/email/src/templates/partner-payout-confirmed.tsx (1)
  • PartnerPayoutConfirmed (24-160)
packages/email/src/index.ts (1)
  • sendBatchEmail (31-70)

@steven-tey steven-tey merged commit b2c5e61 into dubinc:main Dec 8, 2025
3 of 6 checks passed
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.

3 participants