RUM-16394 Pt.2: Implement QuotaChecker for profiling quota HTTP check#3496
Conversation
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
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
QuotaCheckerto perform async quota checks against the quota endpoint and emitQuotaResult. - Introduce
QuotaReasonenum and migrateQuotaResult.reasonfromStringtoQuotaReason(including a newQUOTA_EXCEEDEDpredefined 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.
146ea0f to
972ded7
Compare
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## feature/continuous-profiling #3496 +/- ##
================================================================
+ Coverage 72.41% 72.44% +0.03%
================================================================
Files 980 982 +2
Lines 36268 36352 +84
Branches 6037 6048 +11
================================================================
+ Hits 26261 26334 +73
Misses 8361 8361
- Partials 1646 1657 +11
🚀 New features to boost your workflow:
|
|
@codex review |
There was a problem hiding this comment.
💡 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".
972ded7 to
e5d4bc1
Compare
e5d4bc1 to
fdf7907
Compare
fdf7907 to
4bd33a8
Compare
4bd33a8 to
0152785
Compare
| 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" |
There was a problem hiding this comment.
to confirm that this is deployed in all DCs
| var lastResult: QuotaResult? = null | ||
| private set | ||
|
|
||
| fun checkAsync(sessionId: String, datadogContext: DatadogContext) { |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Yes I agree not to blindly follow browser SDK, we need a clear definition what is fail open for mobile for sure.
There was a problem hiding this comment.
Do you propose to handle this in another PR?
There was a problem hiding this comment.
Since there is a ongoing general discussion about Quota API, any decision we make right now on mobile side may affected by the final result of the discussion. so I purpose to merge as it and leave a TODO here.
| } | ||
| val previousId = lastSessionId.getAndSet(sessionId) | ||
| if (previousId == sessionId) return // same session: in-flight check (if any) is still valid | ||
| pendingFuture.getAndSet(null)?.cancel(true) |
There was a problem hiding this comment.
nb: if it is BackPressureExecutorService or LoggingScheduledThreadPoolExecutor, .cancel will trigger error log entry
There was a problem hiding this comment.
The plan is to use SingleThreadScheduledExecutor to avoid this.
There was a problem hiding this comment.
Then we are losing the executor observability. Not sure if it is important or not though.
0152785 to
55fd32d
Compare
55fd32d to
bbe311c
Compare
3c44c84 to
55852d3
Compare
|
|
||
| // When | ||
| testedChecker.checkAsync(fakeSessionId, fakeDatadogContext) | ||
| awaitCheck() |
There was a problem hiding this comment.
why do we need to await anything, if there are no threads in this setup? same in other similar tests with this call
There was a problem hiding this comment.
The test sets a real newSingleThreadScheduledExecutor so it needs to wait here, moving the FkaeSameThreadExecutorService in this PR so that we can use a fake executor here.
55852d3 to
51c0be4
Compare
What does this PR do?
Implement QuotaChecker for profiling quota HTTP check
Motivation
RUM-16394
Review checklist (to be filled by reviewers)