Skip to content

feat: add X-LaunchDarkly-Instance-Id header (SDK-2356)#162

Open
keelerm84 wants to merge 2 commits into
mainfrom
mk/sdk-2356-instance-id
Open

feat: add X-LaunchDarkly-Instance-Id header (SDK-2356)#162
keelerm84 wants to merge 2 commits into
mainfrom
mk/sdk-2356-instance-id

Conversation

@keelerm84
Copy link
Copy Markdown
Member

@keelerm84 keelerm84 commented May 12, 2026

Summary

Adds the X-LaunchDarkly-Instance-Id header to every outbound polling, streaming, and event request. Value is a v4 UUID generated once in HttpConfigurationBuilderImpl.build() (via UUID.randomUUID()) and applied before user-supplied custom headers, matching the User-Agent / Authorization override convention.

Three pre-existing tests outside the http-config test class were rebuilding HttpConfiguration to derive an "expected" header set for exact-equality comparisons against outbound requests; with per-build UUIDs those assertions were updated to check presence rather than exact equality.

Test plan

  • `./gradlew test --rerun-tasks` — BUILD SUCCESSFUL, full server SDK suite green
  • `./gradlew build -x test` — BUILD SUCCESSFUL (checkstyle, javadoc, shadowJar clean)
  • `make build-contract-tests` — BUILD SUCCESSFUL with `instance-id` capability registered
  • CI green (incl. contract tests across the matrix)

Note

Medium Risk
Touches core request header construction and expands ClientContext API, which could affect all outbound polling/streaming/events requests and any custom integrations relying on context constructors/equals semantics.

Overview
Adds SDK instance identification on requests. The SDK now generates a per-LDClient UUID and threads it through ClientContext, so Components.httpConfiguration() includes X-LaunchDarkly-Instance-Id on outbound requests (while still allowing custom headers to override defaults).

Plumbs the ID through construction and tests. ClientContextImpl.fromConfig ensures the same instance ID is reused across the staged context builds during client initialization, contract-test capabilities advertise instance-id, and several tests were adjusted to assert presence of the header rather than exact header-map equality; HttpConfigurationBuilderTest adds coverage for UUID v4 format, stability within a context, and uniqueness across contexts.

Reviewed by Cursor Bugbot for commit 30cf64b. Bugbot is set up for automated code reviews on this repo. Configure here.

Generate a v4 UUID once per SDK instance in HttpConfigurationBuilderImpl.build
and stamp it on the default headers map. Because the default headers are
shared by the stream, poll, and event paths, every outbound request carries
the same stable per-instance identifier without per-channel plumbing.

Registers the "instance-id" capability with the contract test service so the
cross-SDK harness can verify the header on stream, poll, and event requests.
Updates header-comparison tests that constructed a fresh HttpConfiguration
side-by-side with the one under test; the instance ID is per-build so those
tests now compare other headers exactly and only assert presence of the
instance ID header.
@keelerm84 keelerm84 requested a review from a team as a code owner May 12, 2026 20:59
Generating X-LaunchDarkly-Instance-Id inside HttpConfigurationBuilderImpl.build()
tied the value to a specific subsystem builder. Any code path that goes through
HttpConfiguration would see a value, but other subsystems built from
ClientContext (which is the canonical per-LDClient state holder) had no way to
read the same id.

Add an instanceId field, getter, and a nine-argument constructor variant to
ClientContext. The eight-argument constructor auto-generates a v4 UUID for any
caller that does not need to pass an explicit value; the copy constructor
propagates the existing value, so derived ClientContext instances stay in sync.

ClientContextImpl.fromConfig now generates the UUID once and threads it through
each of the three ClientContext variants it constructs during LDClient init.
HttpConfigurationBuilderImpl reads from ClientContext.getInstanceId() instead
of generating its own. Existing tests in DefaultFeatureRequestorTest /
LDConfigTest / StreamProcessorTest that already accounted for per-build
randomness continue to work because each `clientContext(...)` they construct
gets its own auto-generated id.

Update HttpConfigurationBuilderTest to assert the new contract: the builder
mirrors whatever id the context provides; two distinct ClientContexts produce
distinct ids; one context produces a stable id across multiple builds.

Verified locally with `./gradlew test` against lib/sdk/server: all 17 of 17
test classes pass, including 15 of 15 HttpConfigurationBuilderTest cases.
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default mode and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 30cf64b. Configure here.

this(copyFrom.sdkKey, copyFrom.applicationInfo, copyFrom.http, copyFrom.logging,
copyFrom.offline, copyFrom.serviceEndpoints, copyFrom.threadPriority, copyFrom.wrapperInfo);
copyFrom.offline, copyFrom.serviceEndpoints, copyFrom.threadPriority, copyFrom.wrapperInfo,
copyFrom.instanceId);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Test constructor produces inconsistent instance ID state

Low Severity

The single-arg ClientContext(String sdkKey) constructor calls defaultHttp(sdkKey), which internally creates a temporary ClientContext (auto-generating UUID-A) and builds an HttpConfiguration embedding UUID-A in headers. Then the main constructor delegates to the 8-arg version, which auto-generates a different UUID-B for this.instanceId. This means getInstanceId() returns UUID-B while getHttp().getDefaultHeaders()["X-LaunchDarkly-Instance-Id"] contains UUID-A — an internal inconsistency that could confuse future test authors.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 30cf64b. Configure here.

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