88import com .launchdarkly .sdk .server .interfaces .ServiceEndpoints ;
99import com .launchdarkly .sdk .server .interfaces .WrapperInfo ;
1010
11+ import java .util .UUID ;
12+
1113/**
1214 * Context information provided by the {@link com.launchdarkly.sdk.server.LDClient} when creating components.
1315 * <p>
@@ -31,11 +33,18 @@ public class ClientContext {
3133 private final boolean offline ;
3234 private final ServiceEndpoints serviceEndpoints ;
3335 private final int threadPriority ;
36+ private final String instanceId ;
3437 private WrapperInfo wrapperInfo ;
3538
3639 /**
37- * Constructor that sets all properties. All should be non-null.
38- *
40+ * Constructor that sets all properties including an explicit instance ID. All should be
41+ * non-null.
42+ *
43+ * <p>The instance ID is sent on every outbound request in the {@code X-LaunchDarkly-Instance-Id}
44+ * header. It must be generated once per LDClient and remain stable for the client's lifetime.
45+ * The eight-argument constructor auto-generates a v4 UUID for callers that do not need to
46+ * supply their own value.
47+ *
3948 * @param sdkKey the SDK key
4049 * @param applicationInfo application metadata properties from
4150 * {@link Builder#applicationInfo(com.launchdarkly.sdk.server.integrations.ApplicationInfoBuilder)}
@@ -46,6 +55,7 @@ public class ClientContext {
4655 * {@link Builder#serviceEndpoints(com.launchdarkly.sdk.server.integrations.ServiceEndpointsBuilder)}
4756 * @param threadPriority worker thread priority from {@link Builder#threadPriority(int)}
4857 * @param wrapperInfo wrapper configuration from {@link Builder#wrapper(com.launchdarkly.sdk.server.integrations.WrapperInfoBuilder)}
58+ * @param instanceId per-LDClient identifier for the {@code X-LaunchDarkly-Instance-Id} header
4959 */
5060 public ClientContext (
5161 String sdkKey ,
@@ -55,7 +65,8 @@ public ClientContext(
5565 boolean offline ,
5666 ServiceEndpoints serviceEndpoints ,
5767 int threadPriority ,
58- WrapperInfo wrapperInfo
68+ WrapperInfo wrapperInfo ,
69+ String instanceId
5970 ) {
6071 this .sdkKey = sdkKey ;
6172 this .applicationInfo = applicationInfo ;
@@ -65,19 +76,51 @@ public ClientContext(
6576 this .serviceEndpoints = serviceEndpoints ;
6677 this .threadPriority = threadPriority ;
6778 this .wrapperInfo = wrapperInfo ;
68-
79+ this .instanceId = instanceId ;
80+
6981 this .baseLogger = logging == null ? LDLogger .none () :
7082 LDLogger .withAdapter (logging .getLogAdapter (), logging .getBaseLoggerName ());
7183 }
72-
84+
85+ /**
86+ * Constructor that sets all properties. All should be non-null. Auto-generates a v4 UUID for
87+ * the instance ID; use the nine-argument constructor if you need to thread an existing value
88+ * through (for example, when copying a context for an in-flight LDClient).
89+ *
90+ * @param sdkKey the SDK key
91+ * @param applicationInfo application metadata properties from
92+ * {@link Builder#applicationInfo(com.launchdarkly.sdk.server.integrations.ApplicationInfoBuilder)}
93+ * @param http HTTP configuration properties from {@link Builder#http(ComponentConfigurer)}
94+ * @param logging logging configuration properties from {@link Builder#logging(ComponentConfigurer)}
95+ * @param offline true if the SDK should be entirely offline
96+ * @param serviceEndpoints service endpoint URI properties from
97+ * {@link Builder#serviceEndpoints(com.launchdarkly.sdk.server.integrations.ServiceEndpointsBuilder)}
98+ * @param threadPriority worker thread priority from {@link Builder#threadPriority(int)}
99+ * @param wrapperInfo wrapper configuration from {@link Builder#wrapper(com.launchdarkly.sdk.server.integrations.WrapperInfoBuilder)}
100+ */
101+ public ClientContext (
102+ String sdkKey ,
103+ ApplicationInfo applicationInfo ,
104+ HttpConfiguration http ,
105+ LoggingConfiguration logging ,
106+ boolean offline ,
107+ ServiceEndpoints serviceEndpoints ,
108+ int threadPriority ,
109+ WrapperInfo wrapperInfo
110+ ) {
111+ this (sdkKey , applicationInfo , http , logging , offline , serviceEndpoints , threadPriority ,
112+ wrapperInfo , UUID .randomUUID ().toString ());
113+ }
114+
73115 /**
74116 * Copy constructor.
75- *
117+ *
76118 * @param copyFrom the instance to copy from
77119 */
78120 protected ClientContext (ClientContext copyFrom ) {
79121 this (copyFrom .sdkKey , copyFrom .applicationInfo , copyFrom .http , copyFrom .logging ,
80- copyFrom .offline , copyFrom .serviceEndpoints , copyFrom .threadPriority , copyFrom .wrapperInfo );
122+ copyFrom .offline , copyFrom .serviceEndpoints , copyFrom .threadPriority , copyFrom .wrapperInfo ,
123+ copyFrom .instanceId );
81124 }
82125
83126 /**
@@ -86,20 +129,32 @@ protected ClientContext(ClientContext copyFrom) {
86129 * @param sdkKey the SDK key
87130 */
88131 public ClientContext (String sdkKey ) {
132+ this (sdkKey , UUID .randomUUID ().toString ());
133+ }
134+
135+ // Private delegating constructor: generates a single instance id up front and threads it
136+ // both into the default HttpConfiguration (so the X-LaunchDarkly-Instance-Id default
137+ // header carries it) and into this.instanceId (so getInstanceId() returns the same value).
138+ // The earlier shape, where the public single-arg ctor called defaultHttp(sdkKey) and then
139+ // let the eight-arg ctor auto-generate a fresh UUID, produced two different ids -- one in
140+ // the headers and one returned by getInstanceId().
141+ private ClientContext (String sdkKey , String instanceId ) {
89142 this (
90143 sdkKey ,
91144 new ApplicationInfo (null , null ),
92- defaultHttp (sdkKey ),
145+ defaultHttp (sdkKey , instanceId ),
93146 defaultLogging (),
94147 false ,
95148 Components .serviceEndpoints ().createServiceEndpoints (),
96149 Thread .MIN_PRIORITY ,
97- null
150+ null ,
151+ instanceId
98152 );
99153 }
100-
101- private static HttpConfiguration defaultHttp (String sdkKey ) {
102- ClientContext minimalContext = new ClientContext (sdkKey , null , null , null , false , null , 0 , null );
154+
155+ private static HttpConfiguration defaultHttp (String sdkKey , String instanceId ) {
156+ ClientContext minimalContext = new ClientContext (sdkKey , null , null , null , false , null , 0 , null ,
157+ instanceId );
103158 return Components .httpConfiguration ().build (minimalContext );
104159 }
105160
@@ -199,13 +254,24 @@ public ServiceEndpoints getServiceEndpoints() {
199254 /**
200255 * Returns the worker thread priority that is set by
201256 * {@link Builder#threadPriority(int)}.
202- *
257+ *
203258 * @return the thread priority
204259 */
205260 public int getThreadPriority () {
206261 return threadPriority ;
207262 }
208263
264+ /**
265+ * Returns the per-LDClient instance identifier sent in the {@code X-LaunchDarkly-Instance-Id}
266+ * header on outbound requests. The value is generated once when the {@link ClientContext} is
267+ * constructed and is stable for the client's lifetime.
268+ *
269+ * @return the instance ID
270+ */
271+ public String getInstanceId () {
272+ return instanceId ;
273+ }
274+
209275 /**
210276 * Returns the wrapper information.
211277 *
0 commit comments