fix(telemetry): add circuit breaker and shutdown draining to TelemetryService - #1070
fix(telemetry): add circuit breaker and shutdown draining to TelemetryService#1070edelauna wants to merge 1 commit into
Conversation
📝 WalkthroughWalkthrough
ChangesTelemetry resilience
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Extension
participant TelemetryService
participant TelemetryClient
participant TerminalCleanup
Extension->>TelemetryService: await shutdown()
TelemetryService->>TelemetryService: reject new captures
TelemetryService->>TelemetryClient: drain pending captures
TelemetryService->>TelemetryClient: await shutdown()
TelemetryService-->>Extension: complete or report error
Extension->>TerminalCleanup: continue cleanup
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 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 |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/telemetry/src/__tests__/TelemetryService.shutdown.test.ts (1)
120-144: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider adding a matching test for
captureExceptionshutdown gating.
captureExceptionhas the sameisShuttingDowngate ascaptureEvent(TelemetryService.ts, lines 165-167), but no test here verifies that acaptureExceptioncall is dropped aftershutdown()has started. Add a test mirroring "stops accepting new captures once shutdown() has started" forcaptureException.As per path instructions, "
**/*.{test,spec}.{ts,tsx,js}: Use package-local unit tests for ... error handling."🤖 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 `@packages/telemetry/src/__tests__/TelemetryService.shutdown.test.ts` around lines 120 - 144, Add a package-local unit test alongside “stops accepting new captures once shutdown() has started” that starts TelemetryService.shutdown(), invokes captureException after shutdown begins, awaits shutdown completion, and asserts the mock client’s captureException was not called. Mirror the existing captureEvent gating test while targeting TelemetryService.captureException.Source: Path instructions
🤖 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.
Nitpick comments:
In `@packages/telemetry/src/__tests__/TelemetryService.shutdown.test.ts`:
- Around line 120-144: Add a package-local unit test alongside “stops accepting
new captures once shutdown() has started” that starts
TelemetryService.shutdown(), invokes captureException after shutdown begins,
awaits shutdown completion, and asserts the mock client’s captureException was
not called. Mirror the existing captureEvent gating test while targeting
TelemetryService.captureException.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: da2b6bef-3327-452d-b2d0-3addae8e222f
📒 Files selected for processing (4)
packages/telemetry/src/TelemetryService.tspackages/telemetry/src/__tests__/TelemetryService.circuit-breaker.test.tspackages/telemetry/src/__tests__/TelemetryService.shutdown.test.tssrc/extension.ts
Related GitHub Issue
Refs: #830 (reliability/event-volume-protection half — split from #835; consent/privacy half shipped separately in #1069)
Description
TelemetryServicehad two reliability gaps:CODE_INDEX_ERRORretry loop (e.g. a broken embedder config re-triggering on every file-system event) could flood the PostHog Product Analytics quota with no circuit breaker.deactivate()calledTelemetryService.instance.shutdown()without awaiting it, andshutdown()itself just firedclient.shutdown()on each client without waiting for any in-flightcapture()/captureException()calls to finish first — a capture that started just before shutdown could be silently dropped.This PR adds:
CODE_INDEX_ERROR, tracked independently of all other telemetry: a sliding 10-minute window, trips after 50 occurrences, then suppresses further captures of that event for a 10-minute cooldown before resetting. Unrelated events (TASK_CREATED,TOOL_USED, etc.) are never guarded and can't mask or reset the guarded count.captureEvent/captureExceptionnow track the promise returned by each client'scapture()/captureException()call.shutdown()drains these (looping, not a single snapshot, since draining one call's chain can enqueue more) before callingclient.shutdown(), bounded to a 3-second timeout so a capture stuck on network I/O can't block extension deactivation indefinitely. A rejected capture is caught internally so it never surfaces as an unhandled rejection or blocks the drain.isShuttingDowngate so captures fired aftershutdown()has started are dropped immediately instead of racing the drain loop.src/extension.ts:deactivate()nowawaitsTelemetryService.instance.shutdown(), wrapped in try/catch so a shutdown failure can't skip the remaining terminal cleanup (Terminal.setTerminalProfile,TerminalRegistry.cleanup).Capture call sites (
captureEvent/captureException) remain synchronous/non-blocking for callers — onlyshutdown()awaits the drain.Out of scope
Kept narrow to service-level reliability, per the split from #835:
PRIVACY.md(in fix(telemetry): default telemetry to opt-out with explicit consent UI #1069).Task Completedaggregation (toolsUsed/messageCount),AttemptCompletionToolchanges.modelCache.ts).Test Procedure
pnpm --filter @roo-code/telemetry test: 42/42 passing, including two new files:TelemetryService.circuit-breaker.test.ts— under-threshold pass-through, trip at 50 in-window, cooldown reset, unrelated events don't reset/count toward the guarded total, old occurrences expire out of the window, other event names are never guarded.TelemetryService.shutdown.test.ts— shutdown waits for a pending capture that later resolves, drains a call still in flight across multiple loop passes, stops accepting new captures once shutdown has started, proceeds after the 3s timeout for a never-settling capture, a rejected capture doesn't prevent shutdown from completing.pnpm check-types: clean repo-wide.eslinton all 4 touched files: 0 errors;src/eslint-suppressions.jsonunchanged (no new suppressions).src/__tests__/extension.spec.ts: 4/4 passing, confirming the awaited-shutdown change doesn't break existing deactivation behavior.Pre-Submission Checklist
PRIVACY.mdalready covers the opt-out default via fix(telemetry): default telemetry to opt-out with explicit consent UI #1069).Documentation Updates
Summary by CodeRabbit