-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Retry balance-available cron if there's a pending balance #3051
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.
|
WalkthroughCurrency display in the admin user-info component now converts stored cents to main units before formatting. The payouts balance-available cron route was reworked to schedule a qstash re-check when available balance is zero but pending balance exists, altering pre-payout balance handling and messages. Changes
Sequence Diagram(s)sequenceDiagram
participant Cron as Cron Job
participant Route as balance-available route
participant Stripe as Stripe API
participant Qstash as Qstash Scheduler
Cron->>Route: Invoke balance-available endpoint
Route->>Stripe: Fetch balances (available, pending)
alt available > 0
Route->>Stripe: Create payout
Note right of Route: Apply currency rounding for HUF/TWD if needed
Route-->>Cron: Return payout-created response
else available = 0 and pending > 0
Route->>Qstash: Schedule re-check (delay: 1 hour) with APP_DOMAIN_WITH_NGROK
Note right of Route: Log scheduling & return pending message
Route-->>Cron: Return pending-state response
else available = 0 and pending = 0
Route-->>Cron: Return zero-available-balance message
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 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 |
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
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: 2
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/web/app/(ee)/api/cron/payouts/balance-available/route.ts(2 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: steven-tey
Repo: dubinc/dub PR: 0
File: :0-0
Timestamp: 2025-06-25T21:20:59.837Z
Learning: In the Dub codebase, payout limit validation uses a two-stage pattern: server actions perform quick sanity checks (payoutsUsage > payoutsLimit) for immediate user feedback, while the cron job (/cron/payouts) performs authoritative validation (payoutsUsage + payoutAmount > payoutsLimit) with actual calculated amounts before processing. This design provides fast user feedback while ensuring accurate limit enforcement at transaction time.
Learnt from: TWilson023
Repo: dubinc/dub PR: 2736
File: apps/web/ui/partners/bounties/bounty-logic.tsx:88-96
Timestamp: 2025-08-26T15:03:05.381Z
Learning: In bounty forms, currency values are stored in cents in the backend but converted to dollars when loaded into forms, and converted back to cents when saved. The form logic works entirely with dollar amounts. Functions like generateBountyName that run during save logic receive cent values and need to divide by 100, but display logic within the form should format dollar values directly.
📚 Learning: 2025-08-25T21:41:06.073Z
Learnt from: steven-tey
Repo: dubinc/dub PR: 2758
File: apps/web/app/(ee)/api/cron/payouts/balance-available/route.ts:43-45
Timestamp: 2025-08-25T21:41:06.073Z
Learning: For Stripe API calls on connected accounts, the stripeAccount parameter should be passed in the first parameter object (e.g., stripe.balance.retrieve({ stripeAccount })), not as request options in the second parameter.
Applied to files:
apps/web/app/(ee)/api/cron/payouts/balance-available/route.ts
⏰ 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/payouts/balance-available/route.ts (3)
2-2: LGTM!The new imports are necessary for the qstash retry scheduling feature and enhanced logging/formatting.
Also applies to: 8-13
53-63: LGTM!Enhanced error logging with partner email and stripe account improves debugging, and the
availableBalancevariable name is more descriptive.
92-166: LGTM!The existing payout creation, database updates, and email notification logic remain unchanged and correctly handle the payout flow after the new pending balance checks.
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 (2)
apps/web/app/(ee)/api/cron/payouts/balance-available/route.ts (2)
67-67: Unsafe array access - add bounds check.Accessing
balance.pending[0]without verifying the array has elements will cause a runtime error ifbalance.pendingis empty.Apply this diff to add a safety check:
- const pendingBalance = balance.pending[0].amount; + const pendingBalance = balance.pending?.[0]?.amount ?? 0;
82-85: Use the actual currency instead of hardcoded "USD".The currency formatter is using a hardcoded
"USD"value instead of thecurrencyvariable extracted from the balance on line 63.Apply this diff to use the correct currency:
- `Pending balance found for partner ${partner.email} (${stripeAccount}): ${currencyFormatter(pendingBalance / 100, { currency: "USD" })}. Scheduling another check in 1 hour...`, + `Pending balance found for partner ${partner.email} (${stripeAccount}): ${currencyFormatter(pendingBalance / 100, { currency })}. Scheduling another check in 1 hour...`,
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/web/app/(ee)/admin.dub.co/(dashboard)/components/user-info.tsx(1 hunks)apps/web/app/(ee)/api/cron/payouts/balance-available/route.ts(2 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: steven-tey
Repo: dubinc/dub PR: 0
File: :0-0
Timestamp: 2025-06-25T21:20:59.837Z
Learning: In the Dub codebase, payout limit validation uses a two-stage pattern: server actions perform quick sanity checks (payoutsUsage > payoutsLimit) for immediate user feedback, while the cron job (/cron/payouts) performs authoritative validation (payoutsUsage + payoutAmount > payoutsLimit) with actual calculated amounts before processing. This design provides fast user feedback while ensuring accurate limit enforcement at transaction time.
Learnt from: TWilson023
Repo: dubinc/dub PR: 2736
File: apps/web/ui/partners/bounties/bounty-logic.tsx:88-96
Timestamp: 2025-08-26T15:03:05.381Z
Learning: In bounty forms, currency values are stored in cents in the backend but converted to dollars when loaded into forms, and converted back to cents when saved. The form logic works entirely with dollar amounts. Functions like generateBountyName that run during save logic receive cent values and need to divide by 100, but display logic within the form should format dollar values directly.
📚 Learning: 2025-09-12T17:31:10.548Z
Learnt from: devkiran
Repo: dubinc/dub PR: 2833
File: apps/web/lib/actions/partners/approve-bounty-submission.ts:53-61
Timestamp: 2025-09-12T17:31:10.548Z
Learning: In approve-bounty-submission.ts, the logic `bounty.rewardAmount ?? rewardAmount` is intentional. Bounties with preset reward amounts should use those fixed amounts, and the rewardAmount override parameter is only used when bounty.rewardAmount is null/undefined (for custom reward bounties). This follows the design pattern where bounties are either "flat rate" (fixed amount) or "custom" (variable amount set during approval).
Applied to files:
apps/web/app/(ee)/api/cron/payouts/balance-available/route.ts
📚 Learning: 2025-08-25T21:41:06.073Z
Learnt from: steven-tey
Repo: dubinc/dub PR: 2758
File: apps/web/app/(ee)/api/cron/payouts/balance-available/route.ts:43-45
Timestamp: 2025-08-25T21:41:06.073Z
Learning: For Stripe API calls on connected accounts, the stripeAccount parameter should be passed in the first parameter object (e.g., stripe.balance.retrieve({ stripeAccount })), not as request options in the second parameter.
Applied to files:
apps/web/app/(ee)/api/cron/payouts/balance-available/route.ts
🔇 Additional comments (3)
apps/web/app/(ee)/api/cron/payouts/balance-available/route.ts (3)
2-2: LGTM! Imports are appropriate for the new scheduling functionality.All imported utilities are used correctly in the code.
Also applies to: 8-13
53-61: LGTM! Proper early exit with appropriate error logging.The check for empty available balance array prevents potential undefined access issues downstream.
71-81: LGTM! Qstash scheduling implementation is correct.The retry mechanism properly schedules a re-check in 1 hour when pending balance exists, using the correct delay (3600 seconds) and payload structure.
Summary by CodeRabbit
Bug Fixes
Improvements