Skip to content

Merge develop branch into feature/continuous-profiling branch#3289

Merged
0xnm merged 27 commits into
feature/continuous-profilingfrom
nogorodnikov/merge-develop-into-continuous-profiling-250326
Mar 25, 2026
Merged

Merge develop branch into feature/continuous-profiling branch#3289
0xnm merged 27 commits into
feature/continuous-profilingfrom
nogorodnikov/merge-develop-into-continuous-profiling-250326

Conversation

@0xnm

@0xnm 0xnm commented Mar 25, 2026

Copy link
Copy Markdown
Member

What does this PR do?

This PR does the merge of develop branch into feature/continuous-profiling branch.

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)

hamorillo and others added 24 commits March 23, 2026 09:49
… a dedicated class

Removes the unsafe `as? ResourcesLRUCache` downcast in
`BitmapCachesManager.generateResourceKeyFromDrawable` by separating
key generation into its own abstraction.

Introduces `DrawableKeyGenerator` interface and
`ResourceDrawableKeyGenerator` implementation, which now holds all
the prefix/hash logic previously embedded in `ResourcesLRUCache`.
`BitmapCachesManager` accepts a `DrawableKeyGenerator` as an injected
dependency, eliminating the need to know about the concrete cache type.
…assignments-flags-body

Close flags precomputed assignments body for unsuccessful response
…-paths

Exclude test variant, test fixtures and sample apps folders from code coverage setup
…ing-format

RUM-11445: Fix detekt InvalidStringFormat false alarms
RUM-7740: Extract drawable key generation from ResourcesLRUCache
…tence load

On cold start, if the first network refresh fails, the flags module would
transition to Error instead of Stale even when valid cached flags existed.

Root cause: DefaultFlagsRepository.hasFlags() read atomicState directly
without calling waitForPersistenceLoad(), unlike every other read method.
The persistence latch had not been counted down yet at the moment hasFlags()
was called inside EvaluationsManager, so it returned false and the module
reported Error instead of falling back to cached Stale flags.

Fix: add waitForPersistenceLoad() call in hasFlags(), consistent with all
other read methods. This is bounded to at most persistenceLoadTimeoutMs
(default 100ms) on first call only, on a background executor thread.
- Switch all remaining version = any() stubs to anyOrNull() so the
  persistence callback is actually exercised rather than relying on
  timeout fallback
- Reduce persistenceLoadTimeoutMs from 5000ms to 500ms in async tests
  so regressions fail fast
- Remove flaky lower-bound elapsed-time assertion (currentTimeMillis
  resolution is too coarse on some JVMs)
- Assert capturedCallback non-null before invoking in integration test
  to surface misconfigured mocks immediately
- Assert awaitTermination returns true and call shutdownNow() in finally
  to avoid leaking threads in failing test runs
Both tests previously fired the persistence callback before hasFlags()
was called, meaning they could pass even without the fix. Now:

- Repository test: runs hasFlags() on a background thread and polls
  Thread.State.TIMED_WAITING before firing the callback, ensuring the
  test fails if hasFlags() does not block on the persistence latch.

- Integration test: captures the executor thread via a custom
  ThreadFactory and applies the same TIMED_WAITING poll before firing
  the callback, guaranteeing the executor is blocked in hasFlags() when
  the persistence callback fires.
Polling loops that wait for Thread.State.TIMED_WAITING would spin
forever if hasFlags() returned without blocking (regression), because
the thread would reach TERMINATED rather than TIMED_WAITING. Adding
TERMINATED as a break condition lets the loop exit immediately in the
regression case, after which the assertion fails fast with a clear
error rather than hanging the test suite.
- Assert capturedCallback non-null before invoking in both async
  repository tests, so stubbing mismatches produce an immediate
  clear failure rather than a silent timeout
- Apply TIMED_WAITING wait pattern to the "no data" async test,
  making it verify hasFlags() actually blocks rather than relying
  on a result that is coincidentally false either way
- Add bounded wait (5s) to the executor thread state poll loop in
  the integration test so a null executorThread produces a fast
  failure with a descriptive message instead of an infinite spin
newSingleThreadExecutor keeps its worker thread in WAITING when idle
between tasks, not TERMINATED. If hasFlags() returns without blocking
(regression), the thread finishes and sits in WAITING indefinitely.
The poll loop never exits until the 5s check fires. Adding WAITING as
a break condition makes regressions fail fast on the assertion rather
than spinning for 5 seconds.
The async threading in the two new repository tests and the integration
test was testing implementation details (that hasFlags() blocks) rather
than observable behavior. All that complexity also introduced multiple
rounds of review feedback about race conditions, infinite loops, and
WAITING vs TIMED_WAITING thread states.

Replace with synchronous datastore stubs that fire the callback during
DefaultFlagsRepository construction — the same pattern already used
throughout the test file. The integration test now uses mockExecutorService
(synchronous execution) instead of a real executor. The timeout test
(`persistence callback never fires within timeout`) remains and is the
only test that requires the latch to not be pre-counted-down.
Fix: cold-start stale cache: hasFlags() now waits for persistence load

Co-authored-by: typotter <[email protected]>
…um-schema

RUM-15255: Update RUM schema to include profiling status for RUM errors and operation step vitals
@0xnm
0xnm requested review from a team as code owners March 25, 2026 08:39
ambushwork
ambushwork previously approved these changes Mar 25, 2026

@ambushwork ambushwork left a comment

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.

Can we wait this PR before merging so that I don't have to merge it again : )

@datadog-prod-us1-5

This comment has been minimized.

@codecov-commenter

codecov-commenter commented Mar 25, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 86.36364% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 71.48%. Comparing base (af1a3ee) to head (5730841).

Files with missing lines Patch % Lines
...recorder/resources/ResourceDrawableKeyGenerator.kt 87.50% 1 Missing and 1 partial ⚠️
...s/internal/net/PrecomputedAssignmentsDownloader.kt 0.00% 0 Missing and 1 partial ⚠️
...lags/internal/repository/DefaultFlagsRepository.kt 50.00% 0 Missing and 1 partial ⚠️
...g/android/rum/internal/domain/scope/RumEventExt.kt 75.00% 1 Missing ⚠️
...android/trace/internal/DatadogPropagationHelper.kt 0.00% 1 Missing ⚠️
Additional details and impacted files
@@                       Coverage Diff                        @@
##           feature/continuous-profiling    #3289      +/-   ##
================================================================
- Coverage                         71.49%   71.48%   -0.01%     
================================================================
  Files                               942      943       +1     
  Lines                             34829    34844      +15     
  Branches                           5901     5903       +2     
================================================================
+ Hits                              24899    24906       +7     
+ Misses                             8274     8271       -3     
- Partials                           1656     1667      +11     
Files with missing lines Coverage Δ
...id/profiling/internal/perfetto/PerfettoProfiler.kt 94.02% <100.00%> (+2.43%) ⬆️
...g/android/rum/internal/DatadogLateCrashReporter.kt 89.76% <100.00%> (ø)
...nreplay/internal/recorder/SessionReplayRecorder.kt 95.56% <100.00%> (+0.03%) ⬆️
...internal/recorder/resources/BitmapCachesManager.kt 100.00% <100.00%> (+4.35%) ⬆️
...y/internal/recorder/resources/ResourcesLRUCache.kt 54.55% <ø> (-13.02%) ⬇️
...datadog/android/okhttp/trace/TracingInterceptor.kt 81.94% <ø> (+0.28%) ⬆️
...s/internal/net/PrecomputedAssignmentsDownloader.kt 96.55% <0.00%> (-3.45%) ⬇️
...lags/internal/repository/DefaultFlagsRepository.kt 68.85% <50.00%> (+8.85%) ⬆️
...g/android/rum/internal/domain/scope/RumEventExt.kt 91.81% <75.00%> (-1.24%) ⬇️
...android/trace/internal/DatadogPropagationHelper.kt 66.46% <0.00%> (ø)
... and 1 more

... and 34 files with indirect coverage changes

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

…nd-time

Update profiling telemetry duration, add callback delay data
@ambushwork

Copy link
Copy Markdown
Member

PR is merged, could you pls update the branch?

@0xnm

0xnm commented Mar 25, 2026

Copy link
Copy Markdown
Member Author

@ambushwork done, now it includes profiling telemetry changes

@0xnm
0xnm requested a review from ambushwork March 25, 2026 10:08
@0xnm
0xnm merged commit bf8221b into feature/continuous-profiling Mar 25, 2026
26 checks passed
@0xnm
0xnm deleted the nogorodnikov/merge-develop-into-continuous-profiling-250326 branch March 25, 2026 12:33
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