feat(data-pipeline): add runtime-independent agentless sending - #2389
feat(data-pipeline): add runtime-independent agentless sending#2389rochdev wants to merge 6 commits into
Conversation
📚 Documentation Check Results📦
|
|
✅ All CI checks and tests passed. 🎉 All green!🧪 All tests passed 🎯 Code Coverage (details) 🔗 Commit SHA: cbe142c | Docs | View more details | Give us feedback! |
🔒 Cargo Deny Results📦
|
Artifact Size Benchmark Reportaarch64-alpine-linux-musl
aarch64-unknown-linux-gnu
libdatadog-x64-windows
libdatadog-x86-windows
x86_64-alpine-linux-musl
x86_64-unknown-linux-gnu
|
BenchmarksComparisonBenchmark execution time: 2026-08-26 04:22:48 Comparing candidate commit cbe142c in PR branch Found 6 performance improvements and 10 performance regressions! Performance is the same for 136 metrics, 0 unstable metrics.
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fc9ff139a3
ℹ️ 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".
fc9ff13 to
1c04286
Compare
1c04286 to
52dfcbb
Compare
bengl
left a comment
There was a problem hiding this comment.
Seems fine to me, but @DataDog/apm-common-components-core should probably review.
Implementation changed significantly to keep retries on the Rust side.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 322d9336fe
ℹ️ 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".
There was a problem hiding this comment.
Overall, I'd like to push back against this pull request.
First without the matching libdatadog-nodejs PR it is very hard to reason about which APIs are necessary and which are not.
But more than this, I don't understand why we need the PreparedRequest level of abstraction, and this is not really motivated in the PR description.
What is the goal here
- Is it getting just a bag of data with the request and then doing the http request fully in NodeJS?
- Or is it to have a
send_agentlessfunction that takes messagepack &[u8] serialized trace chunk and uses the existing capabilities implementation to drive calling to the node http stack from rust?
While I am not completely against 1), I would much prefer option 2) as it doesn't expose as much details of libdatadog to nodeJS and you should just be able to hook the exisitng WASM capabilities implementation.
We should just do something like
NodeJS | Rust | NodeJS
send(chunk) -> encode msp -> send(traces: &[u8]) -> encode() -> send_with_retry -> http capability impl
and not
NodeJS | Rust | NodeJS | Rust | NodeJS
prepare(chunk) -> encode msp -> prepare(traces: &[u8]) -> returns prepared request -> send_rust(prepared_request) -> send_with_retry -> http capability
| payload: Bytes, | ||
| headers: HeaderMap, | ||
| compression_strategy: CompressionStrategy, | ||
| } |
There was a problem hiding this comment.
How is this different from an http::Request<Bytes> ?
There was a problem hiding this comment.
Just a small abstraction but it should be effectively equivalent, let me see if I can simplify.
| pin-project = "1" | ||
| libc.workspace = true | ||
| tokio = { workspace = true, features = ["rt", "rt-multi-thread", "macros", "net", "io-util", "fs", "time"] } | ||
| tokio = { workspace = true, features = ["rt", "rt-multi-thread", "macros", "net", "io-util", "fs", "time"], optional = true } |
There was a problem hiding this comment.
Why are these marked as optional. The are already not added for wasm and the codepaths providing the http client are already gated as to compile the crate.
So I don't see how refactoring libdd-common in necessary
There was a problem hiding this comment.
WASM is only half the equation. Without making them explicitly optional, NAPI-RS was still including them. While some things are build target specific, some other things are not and need to be controllable regardless of the target.
| if jitter_ms == 0 { | ||
| delay | ||
| } else { | ||
| let randomized_ms = rand::random::<u64>() % jitter_ms; | ||
| delay.saturating_add(Duration::from_millis(randomized_ms)) | ||
| } |
There was a problem hiding this comment.
This branch here is kind of useless. It is equivalent if the jitter_ms == 0 branch is removed and we gain just a call to random in a case that basically never happens
There was a problem hiding this comment.
I'll try to clean this up.
| /// Converts v0.4 MessagePack traces into a host-transported request. | ||
| pub fn prepare_agentless_v04_request( | ||
| data: &[u8], | ||
| metadata: &TracerMetadata, | ||
| config: &AgentlessTraceConfig, | ||
| ) -> Result<PreparedAgentlessRequest, PrepareAgentlessError> { |
There was a problem hiding this comment.
This is very specific to the way you want to integrate libdatadog in NodeJS, so I would prefer if this function lived in libdatadog-nodejs rather than here.
There was a problem hiding this comment.
Let me try to see if this can be removed.
| compression::add_headers(h, compression_strategy); | ||
| } | ||
| let req = match builder.body(payload.clone()) { | ||
| let req = match prepared.request() { |
There was a problem hiding this comment.
This is not good.
Calling to .request() will do compression on the body but this is inside of the retry loop.
There was a problem hiding this comment.
PreparedRequest handles this so it's not an issue with the current implementation, but I'll try to see if we can remove PrepareRequest completely since half the comments are about it.
What does this PR do?
Adds a runtime-independent agentless data-pipeline send path. Rust owns trace
preparation, JSON encoding, compression, retry policy, timeouts, backoff, and
response handling; the host provides only HTTP and sleep capabilities.
The existing
libdd-data-pipelineexporter now uses the same high-level sendpath, so native and WASM consumers share the behavior without requiring a
specific async runtime.
Motivation
Node.js needs equivalent native and WASM data-pipeline implementations without
embedding Tokio and Hyper in the native extension. Keeping the send lifecycle
in Rust preserves retry behavior and makes the capability boundary reusable by
future targets.
Additional Notes
libdatadog-nodejs.This PR was generated by Codex.
How to test the change?
cargo test -p libdd-data-pipeline-core --features compressioncargo test -p libdd-trace-utils send_with_retrycargo test -p libdd-data-pipeline agentlesscargo clippy -p libdd-data-pipeline-core --all-targets --features compression -- -D warningscargo clippy -p libdd-trace-utils --lib --tests -- -D warningscargo clippy -p libdd-data-pipeline --lib -- -D warnings