-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Move the Resend domain update to queue #3095
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…ia Qstash integration
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Rate limit exceeded@devkiran has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 13 minutes and 37 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (2)
WalkthroughAdds a new cron POST endpoint that updates Resend domain tracking and refactors email-domain creation and update routes to enqueue that work via QStash (delayed) instead of performing Resend updates inline. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant EmailDomainsRoute as /api/email-domains
participant EmailDomainDetail as /api/email-domains/[domain]
participant QStash
participant CronEndpoint as /api/cron/email-domains/update
participant Resend
Client->>EmailDomainsRoute: Create domain
EmailDomainsRoute->>Resend: resend.domains.create()
Resend-->>EmailDomainsRoute: domain created
EmailDomainsRoute->>QStash: publish POST (domainId) with 60s delay
QStash-->>EmailDomainsRoute: messageId (or failure)
EmailDomainsRoute-->>Client: creation response
Client->>EmailDomainDetail: Verify/update domain
EmailDomainDetail->>QStash: publish POST (domainId) with 60s delay
QStash-->>EmailDomainDetail: messageId (or failure)
EmailDomainDetail-->>Client: verify/update response
rect rgb(230,245,255)
Note over QStash,CronEndpoint: After delay
QStash->>CronEndpoint: Deliver POST with domainId (QStash-signed)
CronEndpoint->>CronEndpoint: Verify QStash signature & parse body
CronEndpoint->>Resend: resend.domains.update(openTracking=true, clickTracking=false, tls=true)
Resend-->>CronEndpoint: success or error
CronEndpoint-->>QStash: log success/error
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
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 |
There was a problem hiding this 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 (1)
apps/web/app/(ee)/api/cron/email-domains/update/route.ts (1)
66-69: Log the real error details
JSON.stringify(error)collapsesErrorinstances to{}, so the message we send tolog()drops the actual failure context. Please extract the message/stack before logging so we keep actionable diagnostics.Apply this diff:
- await log({ - message: `Resend email domain update failed with error ${JSON.stringify(error)}`, - type: "errors", - }); + const errorMessage = + error instanceof Error ? `${error.name}: ${error.message}` : JSON.stringify(error); + await log({ + message: `Resend email domain update failed with error ${errorMessage}`, + type: "errors", + });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/web/app/(ee)/api/cron/email-domains/update/route.ts(1 hunks)apps/web/app/(ee)/api/email-domains/route.ts(2 hunks)
⏰ 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
There was a problem hiding this 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
♻️ Duplicate comments (1)
apps/web/app/(ee)/api/email-domains/route.ts (1)
91-115: Surface queue failures instead of silently logging.This is the same concern from the previous review: placing
qstash.publishJSONinsidewaitUntilmeans any queueing failure (missing credentials, network issues, Upstash outage) happens after the 201 response is already sent. The domain gets created but never receives the tracking update, and the caller has no way to detect or retry.Move the publish call into the main request flow so failures are surfaced to the caller.
Apply this diff:
+ const response = await qstash.publishJSON({ + url: `${APP_DOMAIN_WITH_NGROK}/api/cron/email-domains/update`, + method: "POST", + delay: 60, + body: { + domainId: emailDomain.id, + }, + }); + + if (!response.messageId) { + throw new DubApiError({ + code: "internal_server_error", + message: `Failed to queue email domain update for domain ${emailDomain.id}`, + }); + } + waitUntil( (async () => { - // Moving the updates to Qstash because updating the domain immeadiately after creation can fail. - const response = await qstash.publishJSON({ - url: `${APP_DOMAIN_WITH_NGROK}/api/cron/email-domains/update`, - method: "POST", - delay: 1 * 60, // 1 minute delay - body: { - domainId: emailDomain.id, - }, - }); - - if (!response.messageId) { - console.error( - `Failed to queue email domain update for domain ${emailDomain.id}`, - response, - ); - } else { - console.log( - `Queued email domain update for domain ${emailDomain.id}`, - response, - ); - } + console.log( + `Queued email domain update for domain ${emailDomain.id}`, + response.messageId, + ); })(), );
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/web/app/(ee)/api/email-domains/route.ts(2 hunks)
⏰ 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 (1)
apps/web/app/(ee)/api/email-domains/route.ts (1)
6-6: LGTM!The new imports are necessary for queueing domain updates via QStash.
Also applies to: 13-13
There was a problem hiding this 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 (1)
apps/web/app/(ee)/api/email-domains/[domain]/route.ts (1)
74-84: Consider adding monitoring for queue failures.The code only logs when queuing fails but doesn't raise an alert or throw an error. While this is appropriate within a
waitUntilblock, silent queue failures could lead to domains remaining in "pending" status indefinitely without proper updates.Consider implementing monitoring or alerting for queue failures to ensure operational visibility.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/web/app/(ee)/api/email-domains/[domain]/route.ts(2 hunks)
⏰ 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 (3)
apps/web/app/(ee)/api/email-domains/[domain]/route.ts (3)
6-6: LGTM! Imports are appropriate for the queuing mechanism.The new imports for
qstashandAPP_DOMAIN_WITH_NGROKare correctly added to support the background job queuing.Also applies to: 13-13
62-86: The cron endpoint is properly implemented with robust error handling and retry logic.Verification confirms the target endpoint (
/api/cron/email-domains/update) exists and correctly handles the queued domain update. The implementation includes QStash signature verification, domain validation, proper error handling, and automatic retry logic through QStash's error propagation mechanism. The refactoring is sound.
66-66: APP_DOMAIN_WITH_NGROK is correctly configured for production environments.The constant uses a three-tier environment strategy: production resolves to
https://app.${process.env.NEXT_PUBLIC_APP_DOMAIN}, preview resolves tohttps://preview.${process.env.NEXT_PUBLIC_APP_DOMAIN}, and development falls back to ngrok or localhost. The name is potentially misleading (suggesting ngrok is always used), but the implementation explicitly checks for production and resolves to the proper production domain. Queued jobs in production will correctly route to the app domain, not a development tunnel.
…ia Qstash integration
Summary by CodeRabbit
New Features
Improvements