Skip to content

fix(remote-config)!: Expose HttpClientCapability in remote config#2252

Merged
gh-worker-dd-mergequeue-cf854d[bot] merged 4 commits into
mainfrom
bob/rc-native-client
Jul 24, 2026
Merged

fix(remote-config)!: Expose HttpClientCapability in remote config#2252
gh-worker-dd-mergequeue-cf854d[bot] merged 4 commits into
mainfrom
bob/rc-native-client

Conversation

@bwoebi

@bwoebi bwoebi commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

As a side-effect, this fixes the missing timeout on the remote config body awaiting.

@bwoebi
bwoebi requested review from a team as code owners July 17, 2026 16:53
@bwoebi bwoebi changed the title Expose HttpClientCapability in remote config fix(remote-config): Expose HttpClientCapability in remote config Jul 17, 2026
@datadog-datadog-prod-us1

datadog-datadog-prod-us1 Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Tests

🎉 All green!

🧪 All tests passed
❄️ No new flaky tests detected

🎯 Code Coverage (details)
Patch Coverage: 98.70%
Overall Coverage: 74.84% (+0.16%)

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

@datadog-datadog-prod-us1 datadog-datadog-prod-us1 Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Datadog Autotest: PASS

More details

The body_bytes = response.into_body() change is correct: HttpClientCapability::request returns http::Response<bytes::Bytes> with the body fully buffered inside NativeHttpClient, so no further .collect().await is needed. All 24 existing unit tests pass, covering the full fetch pipeline through a local mock HTTP server. The timeout fix is legitimate — the body collection is now inside the timed future, closing a real hang risk in the old code.

Was this helpful? React 👍 or 👎

📊 Validated against 24 scenarios · Open Bits AI session

🤖 Datadog Autotest · Commit 36072ea · What is Autotest? · Any feedback? Reach out in #autotest

@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: 36072ea7cf

ℹ️ 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".

impl<S> ConfigFetcherState<S> {
impl<S> ConfigFetcherState<S, NativeHttpClient> {
pub fn new(invariants: ConfigInvariants) -> Self {
Self::with_client(invariants, NativeHttpClient::new_client())

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 pooling the default remote-config client

With the default constructor, every SingleFetcher/SharedFetcher now stores one NativeHttpClient for the whole polling loop. NativeHttpClient caches a new_default_client() in a OnceLock, and new_default_client() keeps idle connections, while http_common::new_client_periodic() explicitly disables pooling because the agent's low keep-alive can close the pipe on the next periodic request. For default RC polling, this changes the previous per-request client behavior into pooled reuse and can make subsequent polls fail intermittently; please use a periodic/no-idle native client for the default.

Useful? React with 👍 / 👎.

Comment thread libdd-remote-config/src/fetch/single.rs Outdated
Comment on lines 130 to 133
impl<S: FileStorage> SingleChangesFetcher<S, NativeHttpClient>
where
S::StoredFile: FilePath,
{

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 Add a custom-client constructor for SingleChangesFetcher

Although the struct is now generic over C, this only public constructor remains on SingleChangesFetcher<S, NativeHttpClient>, and the private changes field prevents downstream code from constructing SingleChangesFetcher<S, C> around SingleFetcher::with_client. Callers that use the change-tracking API rather than raw fetch_once still cannot inject a custom HttpClientCapability; add a with_client constructor mirroring SingleFetcher::with_client.

Useful? React with 👍 / 👎.

Comment thread libdd-remote-config/Cargo.toml Outdated
client = [
"libdd-trace-protobuf",
"libdd-capabilities",
"libdd-capabilities-impl",

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 force native HTTP for custom clients

Enabling the client feature now always enables libdd-capabilities-impl, even when a downstream only wants to instantiate ConfigFetcherState::with_client with its own HttpClientCapability. I checked libdd-capabilities-impl/src/http.rs, and that implementation imports native-only pieces such as libdd_common::connector::Connector, so custom-client builds for non-native targets still have to compile the native backend and fail before they can supply their own client. Please keep the native implementation behind the default/native constructors or a target-specific dependency instead of making it mandatory for client.

Useful? React with 👍 / 👎.

@bwoebi
bwoebi force-pushed the bob/rc-native-client branch from 36072ea to 39d4b97 Compare July 17, 2026 17:59
@bwoebi
bwoebi requested a review from a team as a code owner July 17, 2026 17:59
@dd-octo-sts

dd-octo-sts Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Artifact Size Benchmark Report

aarch64-alpine-linux-musl
Artifact Baseline Commit Change
/aarch64-alpine-linux-musl/lib/libdatadog_profiling.a 88.33 MB 88.33 MB +0% (+6.33 KB) 👌
/aarch64-alpine-linux-musl/lib/libdatadog_profiling.so 8.13 MB 8.13 MB 0% (0 B) 👌
aarch64-unknown-linux-gnu
Artifact Baseline Commit Change
/aarch64-unknown-linux-gnu/lib/libdatadog_profiling.so 10.94 MB 10.94 MB +0% (+16 B) 👌
/aarch64-unknown-linux-gnu/lib/libdatadog_profiling.a 99.62 MB 99.62 MB +0% (+5.01 KB) 👌
libdatadog-x64-windows
Artifact Baseline Commit Change
/libdatadog-x64-windows/debug/dynamic/datadog_profiling_ffi.dll 26.65 MB 26.65 MB +0% (+1.50 KB) 👌
/libdatadog-x64-windows/debug/dynamic/datadog_profiling_ffi.lib 89.18 KB 89.18 KB 0% (0 B) 👌
/libdatadog-x64-windows/debug/dynamic/datadog_profiling_ffi.pdb 191.80 MB 191.79 MB -0% (-8.00 KB) 👌
/libdatadog-x64-windows/debug/static/datadog_profiling_ffi.lib 1.04 GB 1.04 GB +0% (+22.81 KB) 👌
/libdatadog-x64-windows/release/dynamic/datadog_profiling_ffi.dll 8.68 MB 8.68 MB +.01% (+1.00 KB) 🔍
/libdatadog-x64-windows/release/dynamic/datadog_profiling_ffi.lib 89.18 KB 89.18 KB 0% (0 B) 👌
/libdatadog-x64-windows/release/dynamic/datadog_profiling_ffi.pdb 25.40 MB 25.40 MB 0% (0 B) 👌
/libdatadog-x64-windows/release/static/datadog_profiling_ffi.lib 50.65 MB 50.66 MB +0% (+1.56 KB) 👌
libdatadog-x86-windows
Artifact Baseline Commit Change
/libdatadog-x86-windows/debug/dynamic/datadog_profiling_ffi.dll 23.21 MB 23.22 MB +0% (+2.00 KB) 👌
/libdatadog-x86-windows/debug/dynamic/datadog_profiling_ffi.lib 90.58 KB 90.58 KB 0% (0 B) 👌
/libdatadog-x86-windows/debug/dynamic/datadog_profiling_ffi.pdb 196.50 MB 196.50 MB 0% (0 B) 👌
/libdatadog-x86-windows/debug/static/datadog_profiling_ffi.lib 1.03 GB 1.03 GB +0% (+8.18 KB) 👌
/libdatadog-x86-windows/release/dynamic/datadog_profiling_ffi.dll 6.70 MB 6.70 MB +0% (+512 B) 👌
/libdatadog-x86-windows/release/dynamic/datadog_profiling_ffi.lib 90.58 KB 90.58 KB 0% (0 B) 👌
/libdatadog-x86-windows/release/dynamic/datadog_profiling_ffi.pdb 27.32 MB 27.31 MB --.02% (-8.00 KB) 💪
/libdatadog-x86-windows/release/static/datadog_profiling_ffi.lib 48.23 MB 48.23 MB +0% (+526 B) 👌
x86_64-alpine-linux-musl
Artifact Baseline Commit Change
/x86_64-alpine-linux-musl/lib/libdatadog_profiling.a 78.78 MB 78.78 MB +0% (+680 B) 👌
/x86_64-alpine-linux-musl/lib/libdatadog_profiling.so 9.07 MB 9.07 MB 0% (0 B) 👌
x86_64-unknown-linux-gnu
Artifact Baseline Commit Change
/x86_64-unknown-linux-gnu/lib/libdatadog_profiling.a 94.28 MB 94.28 MB +0% (+168 B) 👌
/x86_64-unknown-linux-gnu/lib/libdatadog_profiling.so 11.04 MB 11.04 MB +0% (+8 B) 👌

@pr-commenter

pr-commenter Bot commented Jul 17, 2026

Copy link
Copy Markdown

Benchmarks

Comparison

Benchmark execution time: 2026-07-24 15:10:47

Comparing candidate commit b71e533 in PR branch bob/rc-native-client with baseline commit 9f2ddb4 in branch main.

Found 2 performance improvements and 4 performance regressions! Performance is the same for 136 metrics, 0 unstable metrics.

Explanation

This is an A/B test comparing a candidate commit's performance against that of a baseline commit. Performance changes are noted in the tables below as:

  • 🟩 = significantly better candidate vs. baseline
  • 🟥 = significantly worse candidate vs. baseline

We compute a confidence interval (CI) over the relative difference of means between metrics from the candidate and baseline commits, considering the baseline as the reference.

If the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD), the change is considered significant.

Feel free to reach out to #apm-benchmarking-platform on Slack if you have any questions.

More details about the CI and significant changes

You can imagine this CI as a range of values that is likely to contain the true difference of means between the candidate and baseline commits.

CIs of the difference of means are often centered around 0%, because often changes are not that big:

---------------------------------(------|---^--------)-------------------------------->
                              -0.6%    0%  0.3%     +1.2%
                                 |          |        |
         lower bound of the CI --'          |        |
sample mean (center of the CI) -------------'        |
         upper bound of the CI ----------------------'

As described above, a change is considered significant if the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD).

For instance, for an execution time metric, this confidence interval indicates a significantly worse performance:

----------------------------------------|---------|---(---------^---------)---------->
                                       0%        1%  1.3%      2.2%      3.1%
                                                  |   |         |         |
       significant impact threshold --------------'   |         |         |
                      lower bound of CI --------------'         |         |
       sample mean (center of the CI) --------------------------'         |
                      upper bound of CI ----------------------------------'

scenario:msgpack_decoder::v05/high_sharing/200

  • 🟩 execution_time [-9.987µs; -9.889µs] or [-5.963%; -5.904%]
  • 🟩 throughput [+74959.747op/s; +75684.153op/s] or [+6.277%; +6.338%]

scenario:profiles_dictionary/profile_string_inserts/threads/1

  • 🟥 execution_time [+18.365µs; +20.958µs] or [+6.150%; +7.018%]
  • 🟥 throughput [-225171.068op/s; -198297.958op/s] or [-6.567%; -5.783%]

scenario:profiles_dictionary/profile_string_inserts/threads/2

  • 🟥 execution_time [+23.354µs; +29.435µs] or [+4.280%; +5.394%]
  • 🟥 throughput [-194004.255op/s; -152689.692op/s] or [-5.169%; -4.068%]

Candidate

Omitted due to size.

Baseline

Omitted due to size.

/// Intended for clients that issue requests on a fixed interval (e.g. remote
/// config polling): the agent's low keep-alive setting can close an idle
/// connection between polls, which turns a pooled/reused connection into
/// intermittent request failures.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I did something similar in libdd-http-client (disable pooling) because of similar comments in Endpoint, but after discussing with agent people, it seems there's no basis for this claim as of today. Might be worth checking if this whole periodic/connection pooling disabling business is really needed at all today.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I don't know, but feels safer to me?

Comment thread libdd-capabilities-impl/src/http.rs Outdated
/// config polling): the agent's low keep-alive setting can close an idle
/// connection between polls, which turns a pooled/reused connection into
/// intermittent request failures.
pub fn new_periodic_client() -> Self {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nit: I think calling it periodic is a bit too specific. At the level of an HTTP client, we don't really care why the caller disable connection pooling. IMHO we should be "lower" level in the description: what we do is that we disable connection pooling.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

So, what exactly would you propose as name then?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

something like disable_connection_pooling if you go for a builder API, or new_no_connection_pooling or something better in that style, which is more factual IMHO

Comment thread libdd-capabilities-impl/src/http.rs Outdated
let client = self
.client
.get_or_init(|| {
if periodic {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nit: I wonder if only having new() for the client, and then with_periodic(self) -> Self or something builder-like wouldn't make the interface a bit lighter.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

... and the callers a bit heavier. I don't quite like this.

@yannham yannham Jul 20, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't think there's a huge difference between new().with_periodic(true) and new_periodic() (or whatever variation depending on the precise names you use). But it's a matter of taste and not very important, so do you as you feel is best 🙂

Comment thread libdd-remote-config/src/fetch/single.rs Outdated
S::StoredFile: FilePath,
{
pub fn new(sink: S, target: Target, runtime_id: String, options: ConfigOptions) -> Self {
pub fn with_client(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nit: I would call that new_with_client. with_client sounds like it should have the signature with_client(self, client: C) -> Self

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agree, this went through some refactor, putting new back.

@bwoebi bwoebi changed the title fix(remote-config): Expose HttpClientCapability in remote config fix(remote-config)!: Expose HttpClientCapability in remote config Jul 20, 2026
bwoebi added 2 commits July 24, 2026 15:39
As a side-effect, this fixes the missing timeout on the remote config body awaiting.

Signed-off-by: Bob Weinand <bob.weinand@datadoghq.com>

# Conflicts:
#	libdd-capabilities-impl/src/http.rs
#	libdd-remote-config/Cargo.toml
Signed-off-by: Bob Weinand <bob.weinand@datadoghq.com>
@bwoebi
bwoebi force-pushed the bob/rc-native-client branch 2 times, most recently from 37a011e to 44fc377 Compare July 24, 2026 14:23
Signed-off-by: Bob Weinand <bob.weinand@datadoghq.com>
@bwoebi
bwoebi force-pushed the bob/rc-native-client branch from 44fc377 to f0f9d5a Compare July 24, 2026 14:30
Signed-off-by: Bob Weinand <bob.weinand@datadoghq.com>
@bwoebi
bwoebi requested a review from a team as a code owner July 24, 2026 14:37
@bwoebi

bwoebi commented Jul 24, 2026

Copy link
Copy Markdown
Contributor Author

/merge

@gh-worker-devflow-routing-ef8351

gh-worker-devflow-routing-ef8351 Bot commented Jul 24, 2026

Copy link
Copy Markdown

View all feedbacks in Devflow UI.

2026-07-24 15:00:08 UTC ℹ️ Start processing command /merge


2026-07-24 15:00:18 UTC ℹ️ MergeQueue: waiting for PR to be ready

This pull request is not mergeable according to GitHub. Common reasons include pending required checks, missing approvals, or merge conflicts — but it could also be blocked by other repository rules or settings.
It will be added to the queue as soon as checks pass and/or get approvals. View in MergeQueue UI.
Note: if you pushed new commits since the last approval, you may need additional approval.
You can remove it from the waiting list with /remove command.


2026-07-24 15:20:07 UTC ℹ️ MergeQueue: merge request added to the queue

The expected merge time in main is approximately 1h (p90).


2026-07-24 16:06:56 UTC 🚨 MergeQueue: This merge request is in error

mergequeue build completed successfully, but the github api returned an error while merging the pr.
GitHub returned an error during the merge attempt. This is a known issue that can often be resolved by retrying the merge request in an hour.

Details

Error: PUT https://api.github.com/repos/DataDog/libdatadog/pulls/2252/merge: 405 Merge already in progress [] (Request ID: C831:14D56A:70DC2:17C27C:6A638D87)

FullStacktrace:
activity error (type: github.GithubService_MergePullRequest, scheduledEventID: 50, startedEventID: 51, identity: 1@github-worker-6db5dd6d7d-jmhzk@): PUT https://api.github.com/repos/DataDog/libdatadog/pulls/2252/merge: 405 Merge already in progress [] (Request ID: C831:14D56A:70DC2:17C27C:6A638D87) (type: GitFailure, retryable: false): PUT https://api.github.com/repos/DataDog/libdatadog/pulls/2252/merge: 405 Merge already in progress [] (type: ErrorResponse, retryable: true)

@pr-shepherd-6ad11f

Copy link
Copy Markdown

PR Shepherd is now watching this PR: fixing basic CI failures, rebasing when it falls behind, and re-queueing after transient merge-queue failures. To disable it, add the pr-shepherd:ignore label.

If you have any questions, reach the team in #ai-devx-flow.

@bwoebi

bwoebi commented Jul 24, 2026

Copy link
Copy Markdown
Contributor Author

/merge

@gh-worker-devflow-routing-ef8351

gh-worker-devflow-routing-ef8351 Bot commented Jul 24, 2026

Copy link
Copy Markdown

View all feedbacks in Devflow UI.

2026-07-24 16:08:02 UTC ℹ️ Start processing command /merge


2026-07-24 16:08:07 UTC ℹ️ MergeQueue: pull request added to the queue

The expected merge time in main is approximately 1h (p90).


2026-07-24 16:52:08 UTCMergeQueue: The checks failed on this merge request

Tests failed on this commit 7ac327f:

What to do next?

  • Investigate the failures and when ready, re-add your pull request to the queue!
  • If your PR checks are green, try to rebase/merge. It might be because the CI run is a bit old.
  • Any question, go check the FAQ.

@bwoebi

bwoebi commented Jul 24, 2026

Copy link
Copy Markdown
Contributor Author

/merge

@gh-worker-devflow-routing-ef8351

gh-worker-devflow-routing-ef8351 Bot commented Jul 24, 2026

Copy link
Copy Markdown

View all feedbacks in Devflow UI.

2026-07-24 16:58:36 UTC ℹ️ Start processing command /merge


2026-07-24 16:58:40 UTC ℹ️ MergeQueue: pull request added to the queue

The expected merge time in main is approximately 1h (p90).


2026-07-24 17:41:30 UTC ℹ️ MergeQueue: This merge request was merged

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants