Skip to content

RUM-16394 Pt.2: Implement QuotaChecker for profiling quota HTTP check#3496

Open
ambushwork wants to merge 1 commit into
feature/continuous-profilingfrom
yl/profiling/add-quota-checker
Open

RUM-16394 Pt.2: Implement QuotaChecker for profiling quota HTTP check#3496
ambushwork wants to merge 1 commit into
feature/continuous-profilingfrom
yl/profiling/add-quota-checker

Conversation

@ambushwork
Copy link
Copy Markdown
Member

What does this PR do?

Implement QuotaChecker for profiling quota HTTP check

Motivation

RUM-16394

Review checklist (to be filled by reviewers)

  • Feature or bugfix MUST have appropriate tests (unit, integration, e2e)
  • Make sure you discussed the feature or bugfix with the maintaining team in an Issue
  • Make sure each commit and the PR mention the Issue number (cf the CONTRIBUTING doc)

@datadog-official

This comment has been minimized.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements a profiling quota HTTP check component (QuotaChecker) and updates the quota result model to use a typed QuotaReason enum, with comprehensive unit tests to validate request building, response parsing, error handling, and deduplication behavior.

Changes:

  • Add QuotaChecker to perform async quota checks against the quota endpoint and emit QuotaResult.
  • Introduce QuotaReason enum and migrate QuotaResult.reason from String to QuotaReason (including a new QUOTA_EXCEEDED predefined result).
  • Add/extend unit tests covering parsing, HTTP errors, request construction, deduplication/reset, last-result behavior, and custom-endpoint bypass.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
features/dd-sdk-android-profiling/src/main/java/com/datadog/android/profiling/internal/quota/QuotaChecker.kt New async HTTP quota checker, parsing, and telemetry logging.
features/dd-sdk-android-profiling/src/main/java/com/datadog/android/profiling/internal/quota/QuotaReason.kt New enum encapsulating quota reasons and raw backend values.
features/dd-sdk-android-profiling/src/main/java/com/datadog/android/profiling/internal/quota/QuotaResult.kt Switch reason to QuotaReason and add QUOTA_EXCEEDED constant.
features/dd-sdk-android-profiling/src/test/kotlin/com/datadog/android/profiling/internal/quota/QuotaCheckerTest.kt New test suite validating QuotaChecker behavior end-to-end with mocked OkHttp.
features/dd-sdk-android-profiling/src/test/kotlin/com/datadog/android/profiling/internal/quota/QuotaResultTest.kt Update tests for QuotaReason-based QuotaResult.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@ambushwork ambushwork force-pushed the yl/profiling/add-quota-checker branch 3 times, most recently from 146ea0f to 972ded7 Compare June 2, 2026 14:49
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Jun 2, 2026

Codecov Report

❌ Patch coverage is 87.91209% with 11 lines in your changes missing coverage. Please review.
✅ Project coverage is 72.43%. Comparing base (1ebad9f) to head (55fd32d).

Files with missing lines Patch % Lines
...g/android/profiling/internal/quota/QuotaChecker.kt 86.08% 6 Missing and 5 partials ⚠️
Additional details and impacted files
@@                       Coverage Diff                        @@
##           feature/continuous-profiling    #3496      +/-   ##
================================================================
+ Coverage                         72.41%   72.43%   +0.02%     
================================================================
  Files                               980      982       +2     
  Lines                             36268    36356      +88     
  Branches                           6037     6049      +12     
================================================================
+ Hits                              26261    26333      +72     
- Misses                             8361     8363       +2     
- Partials                           1646     1660      +14     
Files with missing lines Coverage Δ
...og/android/profiling/internal/quota/QuotaReason.kt 100.00% <100.00%> (ø)
...og/android/profiling/internal/quota/QuotaResult.kt 100.00% <100.00%> (ø)
...g/android/profiling/internal/quota/QuotaChecker.kt 86.08% <86.08%> (ø)

... and 32 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ambushwork
Copy link
Copy Markdown
Member Author

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 972ded7447

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ambushwork ambushwork force-pushed the yl/profiling/add-quota-checker branch from 972ded7 to e5d4bc1 Compare June 3, 2026 12:18
@ambushwork ambushwork marked this pull request as ready for review June 3, 2026 12:26
@ambushwork ambushwork requested review from a team as code owners June 3, 2026 12:26
@ambushwork ambushwork force-pushed the yl/profiling/add-quota-checker branch from e5d4bc1 to fdf7907 Compare June 4, 2026 13:31
abrooksv
abrooksv previously approved these changes Jun 4, 2026
@ambushwork ambushwork force-pushed the yl/profiling/add-quota-checker branch from fdf7907 to 4bd33a8 Compare June 5, 2026 13:33
@ambushwork ambushwork requested a review from satween June 5, 2026 13:33
satween
satween previously approved these changes Jun 5, 2026
@ambushwork ambushwork force-pushed the yl/profiling/add-quota-checker branch from 4bd33a8 to 0152785 Compare June 5, 2026 14:42
@ambushwork ambushwork requested review from abrooksv and satween June 5, 2026 15:49

@Suppress("UnsafeThirdPartyFunctionCall") // Wrapped in the try-catch
private fun buildRequest(sessionId: String, datadogContext: DatadogContext): Request {
val intakeHost = datadogContext.site.intakeEndpoint.removePrefix("https://")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we remove prefix?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because the quota endpoint is https://quota.$intakeHostName and intakeEndpoint is https://$intakeHostName, so we need to remove the prefix to extract the intakeHostName here.

.getJSONObject(JSON_KEY_DATA)
.getJSONObject(JSON_KEY_ATTRIBUTES)
val admitted = attrs.optBoolean(JSON_KEY_ADMITTED, true)
val rawReason = attrs.optString(JSON_KEY_REASON).ifEmpty { null }
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
val rawReason = attrs.optString(JSON_KEY_REASON).ifEmpty { null }
val rawReason = attrs.optString(JSON_KEY_REASON)

default fallback is empty string and rawReason is used only in the parseReason, both null and empty string yield to the same branch there.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

internal const val LOG_UNEXPECTED_ERROR = "Quota check unexpected error: %s"
internal const val LOG_QUOTA_DENIED = "Profiling quota denied: reason=%s"

internal const val QUOTA_URL_TEMPLATE = "https://quota.%s/api/v2/profiling/quota?session_id=%s"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to confirm that this is deployed in all DCs

private set

fun checkAsync(sessionId: String, datadogContext: DatadogContext) {
if (hasCustomEndpoint) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is the use-case for that, who can set it?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is mentioned by @simaoseica-dd before, when user uses custom endpoint, we shouldn't check quota API

var lastResult: QuotaResult? = null
private set

fun checkAsync(sessionId: String, datadogContext: DatadogContext) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what will be the logic behind calling it? for example, we made a call, but got IO exception because there is no network. Obviously, we need to repeat the call, but a) when; b) with back-off?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With current logic, we make a call only when the session is renewed, and we don't retry if there is a network error, because the network error is a fail open according to the browser profiling logic, which can be changed later ofc.

Copy link
Copy Markdown
Member

@0xnm 0xnm Jun 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a concern that browser logic regarding network errors can be be applied to mobile. The fair share of Browser SDK is on the desktop, there is always a connectivity there. Of course mobile browser can be used as well, but once again it should be a connectivity when page is loaded (and probably RUM session is started at this point).

Also Browser profiling requires a document policy sent by the server https://developer.mozilla.org/en-US/docs/Web/API/JS_Self-Profiling_API#security_requirements, this also implies having a connectivity.

}
val previousId = lastSessionId.getAndSet(sessionId)
if (previousId == sessionId) return // same session: in-flight check (if any) is still valid
pendingFuture.getAndSet(null)?.cancel(true)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nb: if it is BackPressureExecutorService or LoggingScheduledThreadPoolExecutor, .cancel will trigger error log entry

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The plan is to use SingleThreadScheduledExecutor to avoid this.

@ambushwork ambushwork force-pushed the yl/profiling/add-quota-checker branch from 0152785 to 55fd32d Compare June 5, 2026 16:53
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.

6 participants