Skip to content

feat: bump OpenFeature to 2.13.0 and implement provider InitializeAsync#203

Open
jonathannorris wants to merge 7 commits into
mainfrom
feat/openfeature-init
Open

feat: bump OpenFeature to 2.13.0 and implement provider InitializeAsync#203
jonathannorris wants to merge 7 commits into
mainfrom
feat/openfeature-init

Conversation

@jonathannorris
Copy link
Copy Markdown
Member

@jonathannorris jonathannorris commented May 4, 2026

Summary

  • Implements InitializeAsync on DevCycleProvider so Api.Instance.SetProviderAsync(...) properly waits for DevCycleLocalClient to finish downloading its initial config before resolving. Without this, early flag evaluations after SetProviderAsync return defaults instead of targeted values.
  • Bumps OpenFeature 2.2.0 → 2.13.0
  • Updates Microsoft.Extensions.Logging.* 8.x → 10.0.0 and System.Text.Json 8/9.x → 10.0.0 (required by OpenFeature 2.13.0; both packages ship net8.0 TFMs so .NET 8 consumers are unaffected)

Motivation

Other DevCycle SDKs already bridge the client initialization signal into the OpenFeature provider's initialize method (Node awaits onClientInitialized(), Java/Python poll with a 2s timeout). The .NET provider was missing this — SetProviderAsync resolved immediately even when the local client hadn't yet fetched its config from the CDN.

Implementation

DevCycleBaseClient gets a new virtual Task InitializeAsync(CancellationToken) that returns Task.CompletedTask by default (Cloud is a no-op). DevCycleLocalClient overrides it to await the init task that was previously fired-and-forgotten in the constructor. DevCycleProvider.InitializeAsync delegates to Client.InitializeAsync, wiring the OpenFeature provider lifecycle into the DevCycle client's readiness signal.

The cancellation path uses WhenAny + TaskCompletionSource to stay compatible with netstandard2.0 (where Task.WaitAsync(CancellationToken) isn't available).

Notes

Requires DevCycleHQ/test-harness#600 to land first — the dotnet proxy needs explicit MEL.Abstractions and System.Text.Json 10.0.0 pins to avoid a NuGet NU1605 conflict in the dotnet/sdk:8.0 Docker image.

Implements InitializeAsync on DevCycleProvider so SetProviderAsync
properly waits for DevCycleLocalClient to finish its initial config
fetch before resolving. Previously, early flag evaluations after
SetProviderAsync returned defaults instead of targeted values.

- DevCycleBaseClient: add virtual InitializeAsync(CancellationToken)
  returning Task.CompletedTask (Cloud is a no-op)
- DevCycleLocalClient: capture init task; override InitializeAsync to
  await it with WhenAny+TaskCompletionSource cancellation (netstandard2.0
  compatible)
- DevCycleProvider: override OpenFeature InitializeAsync, delegating to
  Client.InitializeAsync
- Bump OpenFeature 2.2.0 -> 2.13.0
- Bump Microsoft.Extensions.Logging.* 8.x -> 10.0.0 and System.Text.Json
  8/9.x -> 10.0.0 (required by OpenFeature 2.13.0)
- Update test/benchmark target frameworks net8.0 -> net10.0
@jonathannorris jonathannorris requested a review from a team as a code owner May 4, 2026 17:29
Copilot AI review requested due to automatic review settings May 4, 2026 17:29
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the SDK’s OpenFeature integration so Api.Instance.SetProviderAsync(...) can await the DevCycle Local client’s initial configuration download, preventing early evaluations from returning defaults. It also bumps OpenFeature to 2.13.0 and aligns dependent packages/framework targets to satisfy the newer dependency requirements.

Changes:

  • Implement OpenFeature provider InitializeAsync and add a DevCycleBaseClient.InitializeAsync(...) hook; DevCycleLocalClient now awaits the initial config download task.
  • Upgrade OpenFeature to 2.13.0 and bump related dependencies (Microsoft.Extensions.Logging.*, System.Text.Json) to 10.0.0.
  • Move benchmark/test projects to net10.0 and add a regression test ensuring SetProviderAsync waits for initialization.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
DevCycle.SDK.Server.Local/DevCycle.SDK.Server.Local.csproj Dependency bumps; adds InternalsVisibleTo entry.
DevCycle.SDK.Server.Local/Api/DevCycleLocalClient.cs Tracks and awaits initial config download via InitializeAsync.
DevCycle.SDK.Server.Local.MSTests/DevCycleTest.cs Adds regression test for OpenFeature initialization waiting behavior.
DevCycle.SDK.Server.Local.MSTests/DevCycle.SDK.Server.Local.MSTests.csproj Targets net10.0 and bumps System.Text.Json to 10.0.0.
DevCycle.SDK.Server.Local.Example/DevCycle.SDK.Server.Local.Example.csproj Bumps System.Text.Json to 10.0.0.
DevCycle.SDK.Server.Local.Benchmark/DevCycle.SDK.Server.Local.Benchmark.csproj Targets net10.0 and bumps System.Text.Json to 10.0.0.
DevCycle.SDK.Server.Common/DevCycle.SDK.Server.Common.csproj Bumps OpenFeature to 2.13.0 and updates logging/json dependencies to 10.0.0.
DevCycle.SDK.Server.Common/API/DevCycleProvider.cs Implements InitializeAsync to delegate to client initialization.
DevCycle.SDK.Server.Common/API/DevCycleBaseClient.cs Adds virtual InitializeAsync(...) no-op by default.
DevCycle.SDK.Server.Cloud/DevCycle.SDK.Server.Cloud.csproj Bumps System.Text.Json to 10.0.0.
DevCycle.SDK.Server.Cloud.MSTests/DevCycle.SDK.Server.Cloud.MSTests.csproj Targets net10.0 and bumps System.Text.Json to 10.0.0.
DevCycle.SDK.Server.Cloud.Example/DevCycle.SDK.Server.Cloud.Example.csproj Bumps System.Text.Json to 10.0.0.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread DevCycle.SDK.Server.Local/DevCycle.SDK.Server.Local.csproj Outdated
Comment thread DevCycle.SDK.Server.Local/Api/DevCycleLocalClient.cs Outdated
Comment thread DevCycle.SDK.Server.Local.MSTests/DevCycle.SDK.Server.Local.MSTests.csproj Outdated
Comment thread DevCycle.SDK.Server.Cloud.MSTests/DevCycle.SDK.Server.Cloud.MSTests.csproj Outdated
Comment thread DevCycle.SDK.Server.Local.Benchmark/DevCycle.SDK.Server.Local.Benchmark.csproj Outdated
OpenFeature 2.13.0 requires Microsoft.Extensions.Logging.Abstractions
>= 10.0.0, which conflicts with the test harness Docker image
(dotnet/sdk:8.0). OpenFeature 2.9.0 has the same InitializeAsync API
but only requires MEL >= 8.0.0, staying compatible with .NET 8.

Reverts the over-aggressive dependency bumps to MEL 10.0.0, System.Text.Json
10.0.0, net10.0 TFMs — none of those were needed for the init implementation.
…pins

MEL.Abstractions 10.0.0 and System.Text.Json 10.0.0 both ship net8.0 TFMs,
so they're fully compatible with .NET 8 consumers. The previous attempt
wrongly switched test project TFMs to net10.0 (causing the test harness
dotnet/sdk:8.0 Docker image to fail). This keeps all TFMs at net8.0 and
just pins the package versions that OpenFeature 2.13.0 requires.
- Remove accidental InternalsVisibleTo for OFMultiProviderRepro
- Store InitializeConfigAsync task directly instead of wrapping in Task.Run
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread DevCycle.SDK.Server.Local/DevCycle.SDK.Server.Local.csproj
Comment thread DevCycle.SDK.Server.Local.MSTests/DevCycleTest.cs Outdated
…vior

Uses a gated HttpMessageHandler backed by a TaskCompletionSource to hold
the config response. Verifies SetProviderAsync is pending (not completed)
while initialization is blocked, then releases the gate and confirms flag
evaluation returns a real value — not the default.
Copilot AI review requested due to automatic review settings May 4, 2026 18:15
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +631 to +635
using var dvcClient = DevCycleTestClient.getTestClient();
await OpenFeature.Api.Instance.SetProviderAsync(dvcClient.GetOpenFeatureProvider());
var ctx = EvaluationContext.Builder().Set("user_id", "j_test").Build();
var result = await OpenFeature.Api.Instance.GetClient().GetBooleanValueAsync("test", false, ctx);
Assert.IsTrue(result);
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