Skip to content

[RUM-16386] Add RemoteConfigurationProvider, typed errors, and computed var remoteConfiguration#2980

Open
saraSr5 wants to merge 4 commits into
feature/remote-configfrom
saraSr5/RUM-improvements/remote-config
Open

[RUM-16386] Add RemoteConfigurationProvider, typed errors, and computed var remoteConfiguration#2980
saraSr5 wants to merge 4 commits into
feature/remote-configfrom
saraSr5/RUM-improvements/remote-config

Conversation

@saraSr5

@saraSr5 saraSr5 commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

What and why?

Introduces a set of code quality improvements to the remote configuration layer, following review feedback:

  • RemoteConfigurationProvider protocol — new injectable provider (following the dateProvider pattern) so tests can control the remote configuration value without going through the sync cycle.
  • Typed errors — replaced generic Error with RemoteConfigurationError throughout RemoteConfigurationSynchronizer, with named cases for each failure mode (networkError, httpError, emptyBody, diskError).
  • Computed remoteConfiguration in DatadogCore — replaced the stored property with a computed var backed by the injected provider (priority) with the synchronizer cache as fallback. No more redundant stored state.
  • RemoteConfigurationProvider wired up in DatadogConfiguration and DatadogCore following the exact same injection pattern as dateProvider.

How?

  • RemoteConfigurationProvider protocol added to DatadogInternal and injected into DatadogCore via its designated init, with DefaultRemoteConfigurationProvider as the production default.
  • RemoteConfigurationSynchronizer.cache keeps raw Data (schema validation deferred to RUM-16387); DatadogCore.remoteConfiguration decodes on demand via JSONDecoder.
  • RemoteConfigurationError enum covers all failure paths with typed cases and human-readable errorDescription.

Review checklist

  • Feature or bugfix MUST have appropriate tests (unit, integration)
  • Make sure each commit and the PR mention the Issue number or JIRA reference
  • Add CHANGELOG entry for user facing changes
  • Add Objective-C interface for public APIs - see our guidelines (internal)
  • Run make api-surface when adding new APIs

@datadog-prod-us1-6

This comment has been minimized.

@saraSr5

saraSr5 commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

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

Copy link
Copy Markdown

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: e89baed98b

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

public var remoteConfigurationEndpoint: URL {
// swiftlint:disable:next force_unwrapping
URL(string: "https://sdk-configuration.\(host)/")!
URL(string: "https://cdn.datadoghq.com/rum/")!

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve FedRAMP-specific remote config hosts

When remoteConfigurationID is used with .us1_fed or .us2_fed, this now builds the fetch URL on the commercial cdn.datadoghq.com host instead of a ddog-gov.com host as the previous site-specific implementation did. That bypasses the selected FedRAMP-compatible site for remote configuration requests and also violates the root AGENTS.md rule not to change networking endpoints without explicit approval, so gov-site customers can be routed to the wrong domain.

Useful? React with 👍 / 👎.

@saraSr5

saraSr5 commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

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

Copy link
Copy Markdown

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: 44ec4ce954

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

.appendingPathComponent("abc-123")
.appendingPathExtension("json")
XCTAssertEqual(url.absoluteString, "https://sdk-configuration.browser-intake-datadoghq.com/v1/abc-123.json")
XCTAssertEqual(url.absoluteString, "https://cdn.datadoghq.com/rum/v1/configurations/abc-123")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Fix the remote configuration URL expectation

This assertion now expects https://cdn.datadoghq.com/rum/..., but DatadogSite.us1.remoteConfigurationEndpoint in this same commit still returns https://sdk-configuration.browser-intake-datadoghq.com/, so appending these components produces https://sdk-configuration.browser-intake-datadoghq.com/v1/configurations/abc-123 instead. As written, the endpoint test fails immediately for US1 (and the same mismatch affects the nearby encoding tests), breaking CI even before validating the synchronizer behavior.

Useful? React with 👍 / 👎.

import Foundation

/// Provides the last successfully fetched remote configuration.
public protocol RemoteConfigurationProvider {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep the provider out of the public API

This adds a new public protocol in DatadogInternal (and DatadogCoreProtocol now publicly inherits it), but the repo-level AGENTS.md says “Do NOT introduce new public API without RFC review.” Since this provider is only used as an internal/test injection seam and the API surface/ObjC bridge are not updated in this commit, it leaks a stable SDK API that would need review and compatibility guarantees; make it SPI/internal or route it through the public API process before exposing it.

Useful? React with 👍 / 👎.

@saraSr5 saraSr5 force-pushed the saraSr5/RUM-improvements/remote-config branch from 46e4ba5 to 4dad04f Compare June 9, 2026 14:15
@saraSr5

saraSr5 commented Jun 10, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Breezy!

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@maxep maxep 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.

Looks good, I have left few feedback 👍


/// Owns the remote configuration cache and fetch lifecycle.
/// `nil` when `remoteConfiguration` was not set at init.
internal let synchronizer: RemoteConfigurationSynchronizer?

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.

Lets remove the RemoteConfigurationSynchronizer :)

Comment on lines +51 to +58
func send(request: URLRequest, delegate: URLSessionTaskDelegate?, completion: @escaping (Result<HTTPURLResponse, Error>) -> Void) {
completion(.failure(URLSessionTransportInconsistencyException()))
}

func fetch(request: URLRequest, completion: @escaping (Result<(HTTPURLResponse, Data), Error>) -> Void) {
completion(result)
}
}

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.

I missed this in previous PR, but I think we should rely on a single send method in the protocol HTTPClient with the following signature:

func send(request: URLRequest, delegate: URLSessionTaskDelegate?, completion: @escaping (Result<(HTTPURLResponse, Data?), Error>) -> Void

This clarify the usage and avoid having to provide a default implementation in the protocol extension.

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.

This protocol belongs to theDatadogCore module as it doesn't need to be exposed to feature modules.

}

/// Default implementation that returns no remote configuration.
public struct DefaultRemoteConfigurationProvider: RemoteConfigurationProvider {

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
public struct DefaultRemoteConfigurationProvider: RemoteConfigurationProvider {
public struct NOPRemoteConfigurationProvider: RemoteConfigurationProvider {

@saraSr5

saraSr5 commented Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 👍

Reviewed commit: f481452f8a

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@saraSr5 saraSr5 requested a review from maxep June 12, 2026 12:04

@maxep maxep 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.

Looks great!!

Comment on lines +96 to +97
let error = RemoteConfigurationError.httpError(http.statusCode)
completionHandler(.failure(error))

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.

nit/

Suggested change
let error = RemoteConfigurationError.httpError(http.statusCode)
completionHandler(.failure(error))
completionHandler(.failure(httpError(http.statusCode)))

do {
data = try directory.file(named: "\(id).json").read()
} catch {
return .failure(.diskError)

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.

suggestion/ Lets report a failure to telemetry

@saraSr5 saraSr5 marked this pull request as ready for review June 15, 2026 13:00
@saraSr5 saraSr5 requested review from a team as code owners June 15, 2026 13:00
@saraSr5

saraSr5 commented Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

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

Copy link
Copy Markdown

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: d70251bc51

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".


// TODO RUM-16387: Validate the schema before saving
let remoteConfiguration: RemoteConfiguration
switch Self.decode(data) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid rejecting remote config before caching

When the CDN returns a syntactically valid remote-config JSON that this SDK cannot fully decode yet (for example a new enum value in a server-controlled field), this eager decode returns before the disk write, so the raw document is never cached. That regresses the documented remoteConfigurationID behavior of fetching raw JSON for subsequent launches and makes older SDKs stop updating whenever the remote schema evolves; persist the non-empty body first and decode only when exposing the typed value.

Useful? React with 👍 / 👎.


/// The last successfully fetched remote configuration, if any.
var remoteConfiguration: RemoteConfiguration? {
remoteConfigurationProvider?.remoteConfiguration

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Do not expose post-init remote config fetches

With remoteConfigurationID set, this computed property reads the provider's live cache, which sync() mutates after initialization. If the CDN request finishes before a feature is enabled (for example an app delays RUM.enable or a test uses a local protocol), a first-ever launch can receive a freshly fetched configuration instead of nil, despite the core protocol requiring the document cached at initialization time; this makes remote configuration application depend on network timing, so snapshot the initial cache separately from the async refresh.

Useful? React with 👍 / 👎.

Comment thread DatadogCore/Sources/Datadog.swift Outdated
Comment on lines +478 to +480
remoteConfigurationProvider.sync { result in
if case .failure(let error) = result {
self.telemetry.error("[RemoteConfig] Sync failed", error: error)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3 Badge Capture the core weakly during remote config sync

When remoteConfigurationID is enabled and the CDN request is still in flight, this closure retains DatadogCore until the request completes; the previous path used [weak self]. If an app stops or deinitializes the SDK on a poor network before the request returns, the core and provider stay alive past teardown, so use a weak capture for this telemetry-only callback.

Useful? React with 👍 / 👎.

@saraSr5 saraSr5 requested a review from maxep June 16, 2026 07:01
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.

2 participants