Fix usage credit polling in desktop app#4
Conversation
- Poll worker auth in the desktop app after transcriptions and on a timer - Fetch live billing on `/health/auth` while keeping cached billing for normal auth
|
Warning Rate limit exceeded
To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing. ⌛ 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. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThe desktop app now implements periodic worker authentication polling with post-transcription refresh scheduling. The worker's ChangesWorker Auth & Live Billing Integration
Sequence DiagramsequenceDiagram
participant Desktop App
participant Poll Timer
participant Worker Service
participant Billing System
Poll Timer->>Desktop App: Poll interval fires
Desktop App->>Desktop App: Check if should proceed<br/>(not busy, not already in-flight, signed in)
alt Should proceed
Desktop App->>Worker Service: GET /health/auth<br/>+ poll attempt
Worker Service->>Worker Service: authorizeDesktop({<br/>liveBilling: true })
Worker Service->>Billing System: getBilling(userId)
Billing System-->>Worker Service: Current usage/credits
Worker Service-->>Desktop App: DesktopAuthorization<br/>(with live billing)
Desktop App->>Desktop App: Update auth state
else Skip (logged out, busy, etc.)
Desktop App->>Desktop App: Skip poll
end
Note over Desktop App: Next poll in 5 minutes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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 |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
laryn-transcribe | 0a95cf2 | May 05 2026, 02:45 AM |
|
cursor review |
|
cursor review verbose=true |
|
Bugbot request id: serverGenReqId_123afca4-ca3d-44ab-bf22-04c0d49067fe |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
apps/desktop/main.cjs (1)
625-635: ⚡ Quick winAvoid always firing all three post-transcription retries.
With this PR, each of these timers ends up calling
/health/auth, and/health/authnow does a live Polar billing read. Scheduling all three retries unconditionally means every dictation adds three extra live auth/billing checks even when the first refresh already caught up. Please short-circuit the remaining timers once billing changes, or collapse this to a single delayed retry plus the 5-minute poll.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/desktop/main.cjs` around lines 625 - 635, The current scheduleUsageCreditRefresh schedules all POST_TRANSCRIPTION_USAGE_REFRESH_DELAYS_MS timers unconditionally, causing multiple /health/auth billing reads; change the flow so retries short-circuit once a refresh detects billing changes: update refreshWorkerAuthFromPoll to return a boolean (e.g., true if billing/auth state changed) and in scheduleUsageCreditRefresh replace the fire-and-forget call with an async callback that awaits const changed = await refreshWorkerAuthFromPoll(reason); if changed then call clearUsageCreditRefreshTimers() and exit so remaining timers are cancelled; keep usageCreditRefreshTimers and timer.unref as before so outstanding timers can be cleared safely.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/worker/src/index.ts`:
- Around line 974-976: Replace the unbounded live billing call by wrapping
getBilling(env, device.user_id) in a short timeout (1–2s) and falling back to
getCachedBilling on timeout or error: create a timeout promise (e.g.,
Promise.race with a timer that rejects or resolves after ~1500ms), attempt await
getBilling(...) inside that race, and if the race rejects or throws, catch the
error and call await getCachedBilling(env, device.user_id) instead; log the
timeout/error for observability. Ensure the change targets the billing
resolution logic where options.liveBilling is checked so callers of
getBilling/getCachedBilling (and related flows like
ensurePolarCustomer/withPolarUsageCredits) receive cached billing when live
lookup fails or times out.
---
Nitpick comments:
In `@apps/desktop/main.cjs`:
- Around line 625-635: The current scheduleUsageCreditRefresh schedules all
POST_TRANSCRIPTION_USAGE_REFRESH_DELAYS_MS timers unconditionally, causing
multiple /health/auth billing reads; change the flow so retries short-circuit
once a refresh detects billing changes: update refreshWorkerAuthFromPoll to
return a boolean (e.g., true if billing/auth state changed) and in
scheduleUsageCreditRefresh replace the fire-and-forget call with an async
callback that awaits const changed = await refreshWorkerAuthFromPoll(reason); if
changed then call clearUsageCreditRefreshTimers() and exit so remaining timers
are cancelled; keep usageCreditRefreshTimers and timer.unref as before so
outstanding timers can be cleared safely.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 278a0c0a-9e3f-42b1-845b-d8ccc78a7cab
📒 Files selected for processing (2)
apps/desktop/main.cjsapps/worker/src/index.ts
There was a problem hiding this comment.
2 issues found across 2 files
Confidence score: 3/5
- There is moderate merge risk: two medium-severity findings (6/10) with solid confidence indicate concrete reliability impact rather than just housekeeping.
- In
apps/desktop/main.cjs, busy-state polling can drop scheduled usage-credit refreshes without retry, which risks missing post-transcription billing updates for users. - In
apps/worker/src/index.ts,/health/authperforms a livegetBilling()call without timeout/fallback, so Polar slowness can stall the endpoint and create false health instability. - Pay close attention to
apps/desktop/main.cjsandapps/worker/src/index.ts- retry behavior for deferred billing refreshes and timeout/fallback handling around external billing calls.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/desktop/main.cjs">
<violation number="1" location="apps/desktop/main.cjs:610">
P2: Busy-state polling returns drop scheduled usage-credit refreshes without retry. Defer and retry instead of returning immediately so post-transcription billing updates are not lost.</violation>
</file>
<file name="apps/worker/src/index.ts">
<violation number="1" location="apps/worker/src/index.ts:975">
P2: The live `getBilling()` call in this health-check endpoint has no timeout or fallback. Since `getBilling` reaches an external service (Polar), a slow or degraded response will stall the entire `/health/auth` response, causing the desktop poller to treat the worker as unreachable. Wrap the call with `withTimeout` (already available in this file) and fall back to `getCachedBilling()` on timeout/error.</violation>
</file>
Architecture diagram
sequenceDiagram
participant Desktop as Desktop App (main.cjs)
participant Timer as Auth Poll Timer
participant Worker as Worker (Cloudflare/API)
participant DB as Database
Note over Desktop,DB: Desktop Auth & Billing Refresh Flow
Desktop->>Desktop: configureWorkerAuthPolling()
Desktop->>Timer: setInterval(5 min)
loop Every 5 Minutes
Timer->>Desktop: trigger refreshWorkerAuthFromPoll("interval")
alt Token exists & no poll in flight
alt App is idle (not recording/transcribing/pasting)
Desktop->>Worker: GET /health/auth (Bearer token)
Worker->>Worker: authorizeDesktop(liveBilling=true)
Worker->>DB: getBilling(device.user_id) [live, not cached]
DB-->>Worker: billing data
Worker-->>Desktop: { deviceId, billing, ... }
Desktop->>Desktop: patchStatus with new billing
else App busy
Desktop->>Desktop: skip poll
end
else No token or in flight
Desktop->>Desktop: skip poll
end
end
Note over Desktop,DB: Post-Transcription Credit Refresh
Desktop->>Desktop: transcription:submit result
alt Non-empty transcript
Desktop->>Desktop: scheduleUsageCreditRefresh("transcription-complete")
else Empty transcript
Desktop->>Desktop: scheduleUsageCreditRefresh("transcription-empty")
end
Desktop->>Desktop: clearUsageCreditRefreshTimers()
loop For each delay [5s, 20s, 60s]
Desktop->>Desktop: setTimeout(refreshWorkerAuthFromPoll, delay)
end
Note over Desktop: Each timer fires independently
Desktop->>Worker: GET /health/auth (Bearer token)
Worker->>Worker: authorizeDesktop(liveBilling=true)
Worker->>DB: getBilling(device.user_id) [live]
DB-->>Worker: updated billing (credits synced)
Worker-->>Desktop: fresh billing data
Desktop->>Desktop: patchStatus with new credits
Note over Desktop,DB: Logout / Device Login
Desktop->>Desktop: logoutDevice()
Desktop->>Desktop: clearUsageCreditRefreshTimers()
Desktop->>Desktop: startDeviceLogin()
Desktop->>Desktop: clearUsageCreditRefreshTimers()
Note over Desktop: App quit
Desktop->>Desktop: clearUsageCreditRefreshTimers()
Desktop->>Timer: clearInterval(workerAuthPollTimer)
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
- Skip desktop usage refresh while dictation or auth polling is busy - Add a live billing timeout with cached fallback for desktop auth
Summary
Verification
Summary by CodeRabbit
Release Notes