@@ -10,6 +10,7 @@ import com.datadog.android.Datadog
1010import com.datadog.android.api.InternalLogger
1111import com.datadog.android.api.SdkCore
1212import com.datadog.android.api.feature.FeatureSdkCore
13+ import com.datadog.android.flags.EvaluationContextCallback
1314import com.datadog.android.flags.FlagsClient
1415import com.datadog.android.flags.FlagsStateListener
1516import com.datadog.android.flags.model.FlagsClientState
@@ -93,45 +94,51 @@ class DatadogFlagsProvider private constructor(private val flagsClient: FlagsCli
9394 /* *
9495 * Initializes the provider with the given evaluation context.
9596 *
96- * Sets the initial evaluation context on the underlying [FlagsClient] and waits for
97- * the provider to reach a ready state. Per the OpenFeature spec, this method blocks
98- * until the provider is "ready" - where "ready" means a configuration has been set
99- * and flags have been loaded.
97+ * Per the OpenFeature spec, this method blocks until the provider is "ready" - where
98+ * "ready" means the underlying [FlagsClient] has reached a Ready or Error state.
99+ *
100+ * If an initial context is provided, it will be set on the [FlagsClient] before waiting.
101+ * If no context is provided, the method still waits for the [FlagsClient] to reach
102+ * a ready state (e.g., from a previous setEvaluationContext call or cached data).
100103 *
101104 * The method suspends until the FlagsClient reaches either:
102- * - [FlagsClientState. Ready] : Flags successfully loaded, resumes normally
103- * - [FlagsClientState. Error] : Initialization failed, throws exception
105+ * - Ready: Flags successfully loaded, resumes normally
106+ * - Error: Initialization failed, throws exception
104107 *
105- * @param initialContext The initial evaluation context to set
106- * @throws Exception if initialization fails (FlagsClientState.Error)
108+ * @param initialContext The initial evaluation context to set (optional)
109+ * @throws Exception if initialization fails
107110 */
108111 override suspend fun initialize (initialContext : OpenFeatureEvaluationContext ? ) {
109- if (initialContext == null ) return
112+ suspendCoroutine<Unit > { continuation ->
113+ val callback = object : EvaluationContextCallback {
114+ override fun onSuccess () {
115+ continuation.resume(Unit )
116+ }
110117
111- // Trigger context setting first
112- flagsClient.setEvaluationContext(initialContext.toDatadogEvaluationContext())
118+ override fun onFailure (error : Throwable ) {
119+ continuation.resumeWithException(error)
120+ }
121+ }
113122
114- // Then wait for Ready or Error state
115- suspendCoroutine< Unit > { continuation ->
116- val listener = object : FlagsStateListener {
117- override fun onStateChanged ( newState : FlagsClientState ) {
118- when (newState) {
119- is FlagsClientState . Ready -> {
120- flagsClient.state.removeListener( this )
121- continuation.resume( Unit )
122- }
123- is FlagsClientState . Error -> {
124- flagsClient.state.removeListener( this )
125- continuation.resumeWithException(
126- newState.error ? : Exception ( " Initialization failed " )
127- )
128- }
129- else -> {} // Still waiting (NotReady, Reconciling, Stale )
123+ val datadogContext = initialContext?.toDatadogEvaluationContext()
124+ if (datadogContext != null ) {
125+ flagsClient.setEvaluationContext(datadogContext, callback)
126+ } else {
127+ // No context provided - check if already ready
128+ when (flagsClient.state.getCurrentState()) {
129+ is FlagsClientState . Ready -> continuation.resume( Unit )
130+ is FlagsClientState . Error -> continuation.resumeWithException(
131+ Exception ( " Provider not ready " )
132+ )
133+ else -> {
134+ // Not ready yet - need to wait, but no context to set
135+ // This shouldn't happen in normal flow
136+ continuation.resumeWithException(
137+ Exception ( " Provider initialization requires a context " )
138+ )
130139 }
131140 }
132141 }
133-
134- flagsClient.state.addListener(listener)
135142 }
136143 }
137144
@@ -142,11 +149,7 @@ class DatadogFlagsProvider private constructor(private val flagsClient: FlagsCli
142149 * the provider is ready again or encounters an error. This allows the OpenFeature SDK
143150 * to emit PROVIDER_RECONCILING events while this method executes.
144151 *
145- * The method suspends while the FlagsClient fetches updated flags for the new context,
146- * and resumes when reaching a terminal state:
147- * - [FlagsClientState.Ready]: Flags updated successfully, resumes normally
148- * - [FlagsClientState.Stale]: Network failed but cached flags available, resumes normally
149- * - [FlagsClientState.Error]: Unrecoverable error, throws exception
152+ * Uses the callback API to wait for completion without manual listener management.
150153 *
151154 * @param oldContext The previous evaluation context (unused)
152155 * @param newContext The new evaluation context to set
@@ -156,30 +159,18 @@ class DatadogFlagsProvider private constructor(private val flagsClient: FlagsCli
156159 oldContext : OpenFeatureEvaluationContext ? ,
157160 newContext : OpenFeatureEvaluationContext
158161 ) {
159- // Trigger context change first
160- setContext(newContext)
161-
162- // Then wait for Ready, Stale, or Error state
163162 suspendCoroutine<Unit > { continuation ->
164- val listener = object : FlagsStateListener {
165- override fun onStateChanged (newState : FlagsClientState ) {
166- when (newState) {
167- FlagsClientState .Ready , FlagsClientState .Stale -> {
168- flagsClient.state.removeListener(this )
169- continuation.resume(Unit )
170- }
171- is FlagsClientState .Error -> {
172- flagsClient.state.removeListener(this )
173- continuation.resumeWithException(
174- newState.error ? : Exception (" Context reconciliation failed" )
175- )
176- }
177- else -> {} // Still reconciling (Reconciling, NotReady)
178- }
163+ val callback = object : EvaluationContextCallback {
164+ override fun onSuccess () {
165+ continuation.resume(Unit )
166+ }
167+
168+ override fun onFailure (error : Throwable ) {
169+ continuation.resumeWithException(error)
179170 }
180171 }
181172
182- flagsClient.state.addListener(listener )
173+ flagsClient.setEvaluationContext(newContext.toDatadogEvaluationContext(), callback )
183174 }
184175 }
185176
@@ -349,10 +340,6 @@ class DatadogFlagsProvider private constructor(private val flagsClient: FlagsCli
349340 }
350341 }
351342
352- private fun setContext (context : OpenFeatureEvaluationContext ) {
353- flagsClient.setEvaluationContext(context.toDatadogEvaluationContext())
354- }
355-
356343 companion object {
357344 private const val PROVIDER_NAME = " Datadog Feature Flags Provider"
358345 private const val ERROR_REASON = " ERROR"
0 commit comments