-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Fix cron/withdrawal again #3019
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
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughReplaces a combined payout aggregation with separate aggregates for processing invoices (older than 3 days) and processed payouts, subtracting both from Stripe's available balance to compute withdrawable funds; also adds a count-based guard and test-invoice early return in the charge-succeeded webhook flow. Changes
Sequence Diagram(s)sequenceDiagram
participant Cron as Withdrawal Cron
participant Stripe as Stripe API
participant DB as Prisma (invoices/payouts)
participant PayoutSvc as Payout creation
Note over Cron,Stripe: Trigger cron job
Cron->>Stripe: fetch balance (available)
Cron->>DB: aggregate invoices where status="processing" and createdAt < now-3d
Cron->>DB: aggregate payouts where status="processed"
DB-->>Cron: processingInvoicesAmount, processedPayoutsAmount
Cron->>Cron: amountToKeepOnStripe = processingInvoicesAmount + processedPayoutsAmount
Cron->>Cron: balanceToWithdraw = available - amountToKeepOnStripe
alt balanceToWithdraw > threshold
Cron->>PayoutSvc: create payout
PayoutSvc-->>Cron: payout created
else
Cron-->>Cron: no payout created
end
sequenceDiagram
participant Webhook as Stripe webhook handler
participant DB as Prisma (payouts)
participant Q as Qstash publisher
Webhook->>Webhook: receive charge.succeeded invoice
alt invoice.id == TEST_INVOICE_ID
Webhook-->>Webhook: log skip and return
else
Webhook->>DB: count payouts to process for invoice
DB-->>Webhook: payoutsToProcess
alt payoutsToProcess == 0
Webhook-->>Webhook: log "no payouts to process" and return
else
Webhook->>Q: publish payout job
Q-->>Webhook: queued
end
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 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 |
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 (2)
apps/web/app/(ee)/api/cron/trigger-withdrawal/route.ts (2)
28-28: Optimize date calculation for clarity and efficiency.The nested
new Date()calls create unnecessary objects. Consider refactoring for better readability and minor performance improvement.Apply this diff:
- lt: new Date(new Date().setDate(new Date().getDate() - 3)), + lt: new Date(Date.now() - 3 * 24 * 60 * 60 * 1000),Or for better clarity:
+ const threeDaysAgo = new Date(); + threeDaysAgo.setDate(threeDaysAgo.getDate() - 3); + createdAt: { // Why we're doing this: ACH payments usually take up to 4 business days to settle // but in case it settles earlier, we'd want to keep the balance on Stripe for payouts // So, we're including "processing" invoices created more than 3 days ago in the reserve balance as well - lt: new Date(new Date().setDate(new Date().getDate() - 3)), + lt: threeDaysAgo, },
35-52: Add comment explaining processed payouts reserve logic.The comment on lines 25-27 explains why processing invoices are reserved, but there's no explanation for why processed payouts need to be kept on Stripe. This could confuse future developers.
Consider adding a comment to clarify the business logic:
prisma.payout.aggregate({ where: { + // Keep processed payouts in reserve because Stripe payouts can take time to complete + // and the funds may still be in the Stripe account even though marked "processed" in our DB status: "processed", }, _sum: { amount: true, }, }),
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/web/app/(ee)/api/cron/trigger-withdrawal/route.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
apps/web/app/(ee)/api/cron/trigger-withdrawal/route.ts (2)
apps/web/lib/stripe/index.ts (1)
stripe(4-10)packages/prisma/index.ts (1)
prisma(3-9)
⏰ 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/cron/trigger-withdrawal/route.ts (3)
18-46: LGTM! Efficient parallel fetching with solid refactoring.The refactoring to separate invoice and payout aggregation is clean and the use of
Promise.allensures efficient parallel execution. The logic correctly distinguishes between processing invoices and processed payouts for reserve calculation.Minor note: Lines 45-46 access
stripeBalanceData.available[0]andstripeBalanceData.pending[0]without bounds checking. While Stripe always returns at least one balance object, consider adding a runtime check or assertion for defensive programming.
48-52: LGTM! Proper null safety handling.The nullish coalescing operator (
?? 0) correctly handles cases where aggregates return null (when no records match), preventing potential runtime errors.
72-75: Note: Currency is hardcoded to USD.The payout creation assumes USD currency, which aligns with accessing
stripeBalanceData.available[0]on line 45. This is fine for current requirements, but be aware that adding multi-currency support would require refactoring this logic to handle multiple balances.
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
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/web/app/(ee)/api/stripe/webhook/charge-succeeded.ts(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
apps/web/app/(ee)/api/stripe/webhook/charge-succeeded.ts (1)
packages/prisma/index.ts (1)
prisma(3-9)
⏰ 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 (2)
apps/web/app/(ee)/api/stripe/webhook/charge-succeeded.ts (2)
7-7: LGTM!The
logimport is necessary for the new invoice guard and follows the existing import pattern.
57-68: Nice optimization!Replacing
findManywithcountis more efficient since only the count is needed to determine whether to proceed. The updated log message is also more descriptive.
|
/bug0 run |
2 similar comments
|
/bug0 run |
|
/bug0 run |
Summary by CodeRabbit