Skip to content

[PROF-13798] [Browser Profiler] Quota check#4514

Draft
thomasbertet wants to merge 10 commits intomainfrom
thomas.bertet/PROF-13798-profiling-quota-in-sdk
Draft

[PROF-13798] [Browser Profiler] Quota check#4514
thomasbertet wants to merge 10 commits intomainfrom
thomas.bertet/PROF-13798-profiling-quota-in-sdk

Conversation

@thomasbertet
Copy link
Copy Markdown
Collaborator

@thomasbertet thomasbertet commented Apr 21, 2026

Motivation

Adds client-side enforcement of the per-org profiling quota by calling the quota admission API before allowing profiling data to be sent. Ticket: PROF-13798.

Changes

  • New quotaCheck.ts: calls GET /api/unstable/profiling/admission?session_id=<id>&dd-api-key=<token>. Returns 'quota-ok' (HTTP 200, timeout, network error — fail-open) or 'quota-exceeded' (HTTP 429). 5 s client-side timeout via AbortController + Promise.race. Uses the Zone.js-safe fetch wrapper from @datadog/browser-core.
  • profiler.ts: profiler starts recording immediately (optimistic), quota check fires in parallel. On quota-exceeded: profiler stops, trace is discarded (no data sent), _dd.profiling.error_reason is set to 'quota-exceeded' on RUM events. A generation counter prevents stale results from a prior session applying to a new one. SESSION_RENEWED now also restarts on quota-exceeded so quota is re-checked on session renewal.
  • rumProfiler.types.ts: adds 'quota-exceeded' to RumProfilerStoppedInstance.stateReason.

Temporary Note: _dd.profiling.error_reason: 'quota-exceeded' is passed with as any until the rum-events-format schema is updated in a rum-events-format PR.

Test instructions

  • Unit tests: yarn test:unit --spec packages/rum/src/domain/profiling/quotaCheck.spec.ts (5 tests)
  • Unit tests: yarn test:unit --spec packages/rum/src/domain/profiling/profiler.spec.ts (25 tests, includes 8 new quota check scenarios)
  • Verify _dd.profiling.error_reason: 'quota-exceeded' appears on RUM events when the quota API returns 429

Checklist

  • Added unit tests for this change.
  • Tested locally
  • Tested on staging
  • Added e2e/integration tests for this change.
  • Updated documentation and/or relevant AGENTS.md file

New module that calls GET /api/unstable/profiling/admission with the
RUM session ID. Returns 'quota-ok' (HTTP 200, timeout, network error)
or 'quota-exceeded' (HTTP 429). Client-side 5s timeout via
AbortController + Promise.race. Uses the Zone.js-safe fetch wrapper
from @datadog/browser-core.
Profiler starts recording immediately (optimistic), then fires
checkProfilingQuota() in parallel. On quota-exceeded (HTTP 429):
- Profiler stops and discards the in-flight trace (no data sent)
- _dd.profiling.error_reason is set to 'quota-exceeded' on RUM events

Stale results (from a prior session) are discarded via a generation
counter incremented on each start(). Within-session cancellation
(user stop, session expiry) is handled by an instance state guard.

SESSION_RENEWED now also restarts the profiler when it was stopped
due to quota-exceeded, re-checking quota for the new session.
@thomasbertet thomasbertet changed the title [PROF-13798] ✨ Gate profiling on quota admission API [PROF-13798] [Browser Profiler] Quota check Apr 21, 2026
@datadog-prod-us1-4
Copy link
Copy Markdown

datadog-prod-us1-4 Bot commented Apr 21, 2026

Tests

Fix all issues with BitsAI or with Cursor

⚠️ Warnings

🧪 13 Tests failed

checkProfilingQuota builds the URL with site and session_id from Chrome 63.0.3239.84 (Windows 10)   View in Datadog   (Fix with Cursor)
ReferenceError: AbortController is not defined
    at checkProfilingQuota (webpack:///packages/rum/src/domain/profiling/quotaCheck.ts:19:22 <- /tmp/_karma_webpack_321698/commons.js:111848:24)
    at UserContext.it (webpack:///packages/rum/src/domain/profiling/quotaCheck.spec.ts:52:30 <- /tmp/_karma_webpack_321698/commons.js:111811:79)
    at <Jasmine>
checkProfilingQuota returns quota-exceeded on HTTP 429 from Chrome 63.0.3239.84 (Windows 10)   View in Datadog   (Fix with Cursor)
ReferenceError: AbortController is not defined
    at checkProfilingQuota (webpack:///packages/rum/src/domain/profiling/quotaCheck.ts:19:22 <- /tmp/_karma_webpack_321698/commons.js:111848:24)
    at UserContext.it (webpack:///packages/rum/src/domain/profiling/quotaCheck.spec.ts:28:45 <- /tmp/_karma_webpack_321698/commons.js:111790:94)
    at <Jasmine>
checkProfilingQuota returns quota-ok on HTTP 200 from Chrome 63.0.3239.84 (Windows 10)   View in Datadog   (Fix with Cursor)
ReferenceError: AbortController is not defined
    at checkProfilingQuota (webpack:///packages/rum/src/domain/profiling/quotaCheck.ts:19:22 <- /tmp/_karma_webpack_321698/commons.js:111848:24)
    at UserContext.it (webpack:///packages/rum/src/domain/profiling/quotaCheck.spec.ts:20:45 <- /tmp/_karma_webpack_321698/commons.js:111783:94)
    at <Jasmine>
View all

ℹ️ Info

No other issues found (see more)

❄️ No new flaky tests detected

🎯 Code Coverage (details)
Patch Coverage: 75.00%
Overall Coverage: 77.01% (-0.03%)

Useful? React with 👍 / 👎

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: c271da4 | Docs | Datadog PR Page | Give us feedback!

Expose clientToken on TransportConfiguration so it is accessible from
RumConfiguration downstream. Previously clientToken was only available
at init time when building endpoint builders, making it inaccessible
from the profiler chunk.

Also run Prettier on the two spec files that had formatting issues.
@cit-pr-commenter-54b7da
Copy link
Copy Markdown

cit-pr-commenter-54b7da Bot commented Apr 21, 2026

Bundles Sizes Evolution

📦 Bundle Name Base Size Local Size 𝚫 𝚫% Status
Rum 179.16 KiB 179.19 KiB +26 B +0.01%
Rum Profiler 6.16 KiB 7.09 KiB +957 B +15.18%
Rum Recorder 27.03 KiB 27.03 KiB 0 B 0.00%
Logs 56.65 KiB 56.67 KiB +26 B +0.04%
Rum Slim 135.00 KiB 135.03 KiB +26 B +0.02%
Worker 23.63 KiB 23.63 KiB 0 B 0.00%
🚀 CPU Performance

Pending...

🧠 Memory Performance

Pending...

🔗 RealWorld

…eckProfilingQuota

Move client token from dd-api-key query param to DD-CLIENT-TOKEN header
to avoid leaking it in URL logs. Add getQuotaBaseURL() to resolve the
correct base per site (datad0g.com uses dd.datad0g.com, others use
app.<site>). Add credentials: 'omit' to suppress cookie sending.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant