Skip to content

Commit 5a499fd

Browse files
leoromanovskyBridgeAR
authored andcommitted
feat(openfeature): support agentless feature flag configuration (#9397)
Feature flag configuration can now be delivered from the agentless endpoint while keeping startup lazy and polling cancellable. The source retains the last known-good response when polling fails and avoids assembling unrelated JSON fields during streaming responses.
1 parent 45e9ecf commit 5a499fd

34 files changed

Lines changed: 2898 additions & 369 deletions

.github/CODEOWNERS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,8 @@
370370
/packages/dd-trace/src/bootstrap.js @DataDog/lang-platform-js
371371
/packages/dd-trace/src/feature-registry.js @DataDog/lang-platform-js
372372
/packages/dd-trace/src/exporters/common/ @DataDog/lang-platform-js
373+
/packages/dd-trace/src/exporters/common/client-library-headers.js @DataDog/lang-platform-js @DataDog/feature-flagging-and-experimentation-sdk
374+
/packages/dd-trace/src/proxy.js @DataDog/lang-platform-js
373375
/packages/dd-trace/test/agent/ @DataDog/lang-platform-js
374376
/packages/dd-trace/test/dd-trace.spec.js @DataDog/lang-platform-js
375377
/packages/dd-trace/test/dogstatsd.spec.js @DataDog/lang-platform-js

index.d.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -156,12 +156,12 @@ interface Tracer extends opentracing.Tracer {
156156
llmobs: tracer.llmobs.LLMObs;
157157

158158
/**
159-
* OpenFeature Provider with Remote Config integration.
159+
* OpenFeature Provider with agentless and Agent Remote Config delivery.
160160
*
161-
* Extends DatadogNodeServerProvider with Remote Config integration for dynamic flag configuration.
162-
* Enable with DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED=true.
161+
* Agentless delivery is enabled by default and starts when the provider is first accessed.
163162
*
164-
* @env DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED
163+
* @env DD_FEATURE_FLAGS_ENABLED
164+
* @env DD_FEATURE_FLAGS_CONFIGURATION_SOURCE
165165
* @beta This feature is in preview and not ready for production use
166166
*/
167167
openfeature: tracer.OpenFeatureProvider;
@@ -799,9 +799,9 @@ declare namespace tracer {
799799
*/
800800
flaggingProvider?: {
801801
/**
802-
* Whether to enable the feature flagging provider.
803-
* Requires Remote Config to be properly configured.
804-
* Can be configured via DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED environment variable.
802+
* Legacy feature flagging provider switch.
803+
* When the stable Feature Flags configuration is unset, true selects Agent Remote Config and false disables
804+
* the provider.
805805
*
806806
* @default false
807807
* @env DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED
@@ -1620,7 +1620,7 @@ declare namespace tracer {
16201620
/**
16211621
* Flagging Provider (OpenFeature-compatible).
16221622
*
1623-
* Wraps @datadog/openfeature-node-server with Remote Config integration for dynamic flag configuration.
1623+
* Wraps @datadog/openfeature-node-server with agentless and Agent Remote Config delivery.
16241624
* Implements the OpenFeature Provider interface for flag evaluation.
16251625
*
16261626
* @beta This feature is in preview and not ready for production use

index.d.v5.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -156,12 +156,12 @@ interface Tracer extends opentracing.Tracer {
156156
llmobs: tracer.llmobs.LLMObs;
157157

158158
/**
159-
* OpenFeature Provider with Remote Config integration.
159+
* OpenFeature Provider with agentless and Agent Remote Config delivery.
160160
*
161-
* Extends DatadogNodeServerProvider with Remote Config integration for dynamic flag configuration.
162-
* Enable with DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED=true.
161+
* Agentless delivery is enabled by default and starts when the provider is first accessed.
163162
*
164-
* @env DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED
163+
* @env DD_FEATURE_FLAGS_ENABLED
164+
* @env DD_FEATURE_FLAGS_CONFIGURATION_SOURCE
165165
* @beta This feature is in preview and not ready for production use
166166
*/
167167
openfeature: tracer.OpenFeatureProvider;
@@ -869,9 +869,9 @@ declare namespace tracer {
869869
*/
870870
flaggingProvider?: {
871871
/**
872-
* Whether to enable the feature flagging provider.
873-
* Requires Remote Config to be properly configured.
874-
* Can be configured via DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED environment variable.
872+
* Legacy feature flagging provider switch.
873+
* When the stable Feature Flags configuration is unset, true selects Agent Remote Config and false disables
874+
* the provider.
875875
*
876876
* @default false
877877
* @env DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED
@@ -1732,7 +1732,7 @@ declare namespace tracer {
17321732
/**
17331733
* Flagging Provider (OpenFeature-compatible).
17341734
*
1735-
* Wraps @datadog/openfeature-node-server with Remote Config integration for dynamic flag configuration.
1735+
* Wraps @datadog/openfeature-node-server with agentless and Agent Remote Config delivery.
17361736
* Implements the OpenFeature Provider interface for flag evaluation.
17371737
*
17381738
* @beta This feature is in preview and not ready for production use
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
'use strict'
2+
3+
const tracer = require('dd-trace')
4+
5+
const { once } = require('node:events')
6+
const http = require('node:http')
7+
8+
const { OpenFeature } = require('@openfeature/server-sdk')
9+
10+
const {
11+
TEST_DEFAULT_VALUE,
12+
TEST_FLAG_KEY,
13+
TEST_SERVICE,
14+
TEST_TARGETING_KEY,
15+
} = process.env
16+
17+
tracer.init({
18+
env: 'integration',
19+
flushInterval: 0,
20+
service: TEST_SERVICE,
21+
})
22+
23+
let client
24+
25+
/**
26+
* @param {object} message
27+
* @param {'access'|'evaluate'|'trace'} message.command
28+
* @param {string} [message.spanName]
29+
* @param {string} [message.url]
30+
* @param {boolean} [message.waitForReady]
31+
*/
32+
async function handleMessage (message) {
33+
try {
34+
if (message.command === 'access') {
35+
const provider = tracer.openfeature
36+
if (message.waitForReady) {
37+
await OpenFeature.setProviderAndWait(provider)
38+
} else {
39+
OpenFeature.setProvider(provider)
40+
}
41+
client = OpenFeature.getClient()
42+
send({ accessed: true })
43+
return
44+
}
45+
46+
if (message.command === 'evaluate') {
47+
const details = await client.getStringDetails(TEST_FLAG_KEY, TEST_DEFAULT_VALUE, {
48+
targetingKey: TEST_TARGETING_KEY,
49+
userId: TEST_TARGETING_KEY,
50+
})
51+
send({ details })
52+
return
53+
}
54+
55+
if (message.command === 'trace') {
56+
await tracer.trace(message.spanName, async () => {
57+
if (message.url) {
58+
const request = http.get(message.url)
59+
const [response] = await once(request, 'response')
60+
response.resume()
61+
await once(response, 'end')
62+
}
63+
})
64+
send({ traced: true })
65+
}
66+
} catch (error) {
67+
send({ error: error.stack || error.message })
68+
}
69+
}
70+
71+
/**
72+
* @param {object} message
73+
*/
74+
function send (message) {
75+
process.send?.({ port: 0, ...message })
76+
}
77+
78+
process.on('message', handleMessage)
79+
send({ ready: true })

0 commit comments

Comments
 (0)