Skip to content

fix: Resolve initialization immediately when a start wait time was used - #66

Merged
kinyoklion merged 1 commit into
mainfrom
devin/1787954411-dotnet-start-wait-immediate
Sep 1, 2026
Merged

fix: Resolve initialization immediately when a start wait time was used#66
kinyoklion merged 1 commit into
mainfrom
devin/1787954411-dotnet-start-wait-immediate

Conversation

@kinyoklion

@kinyoklion kinyoklion commented Aug 28, 2026

Copy link
Copy Markdown
Member

BEGIN_COMMIT_OVERRIDE
chore: Resolve initialization immediately when a start wait time was used
END_COMMIT_OVERRIDE

Change to chore as it is being reverted.

A positive StartWaitTime no longer causes a second wait during provider initialization.

  • The provider constructor already blocks in the LdClient constructor for the start wait time, so InitializeAsync now completes with the outcome instead of scheduling its own timer; a 5 second start wait no longer means up to 10 seconds before SetProviderAsync resolves.
  • A zero StartWaitTime is unchanged: no timeout, initialization completes when the data source becomes valid or fails permanently.
  • The failure message changed to the client did not become ready within the {n}ms start wait time.
Implementation details

Follow-up to #60, which introduced the timeout. ScheduleInitTimeout is replaced by FailInitializationIfNotReady, called at the end of InitializeAsync when a start wait was configured:

if (_startWait.HasValue)
{
    FailInitializationIfNotReady(_startWait.Value);
}

The provider still keeps listening for data source status after failing, so a later successful connection emits a ready event and evaluations are never short-circuited.

Testing: dotnet test test/LaunchDarkly.OpenFeature.ServerProvider.Tests -f net8.0. The timeout test now asserts the immediate failure, and the "does not time out when the client becomes ready" test covers a client which is ready when initialization is requested.

Related spec change: https://github.com/launchdarkly/sdk-specs/pull/257

Link to Devin session: https://app.devin.ai/sessions/0c452d209ec54b068ba120b4c92b8f6c
Open in Devin Desktop: https://app.devin.ai/desktop/session/0c452d209ec54b068ba120b4c92b8f6c?variant=devin
Requested by: @kinyoklion


Note

Overview
Fixes double-wait on provider startup when StartWaitTime is greater than zero. The LaunchDarkly client already blocks in the provider constructor for that duration; InitializeAsync no longer schedules a second timer, so a 5s start wait no longer stretches toward ~10s before SetProviderAsync completes.

When a start wait is configured and the client is still not ready after construction, InitializeAsync fails synchronously with an updated message (the client did not become ready within the {n}ms start wait time). Background reconnection is unchanged—a later successful connection can still emit a ready event. StartWaitTime of zero still means non-blocking construction and async initialization until the data source is valid.

README initialization notes are aligned with this behavior; unit tests assert immediate failure and the ready-client success path.

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

Co-Authored-By: rlamb@launchdarkly.com <4955475+kinyoklion@users.noreply.github.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@devin-ai-integration

Copy link
Copy Markdown
Contributor

@cursor review

@kinyoklion
kinyoklion marked this pull request as ready for review August 31, 2026 21:16
@kinyoklion
kinyoklion requested a review from a team as a code owner August 31, 2026 21:16
@kinyoklion
kinyoklion merged commit 11b9f68 into main Sep 1, 2026
11 checks passed
@kinyoklion
kinyoklion deleted the devin/1787954411-dotnet-start-wait-immediate branch September 1, 2026 15:52
kinyoklion added a commit that referenced this pull request Sep 1, 2026
…ion (#68)

Intentionally chore. I am removing the changelog as it has not been
released.

Reverts #60 and #66, restoring the pre-2.2.0 initialization behavior.

- `StartWaitTime` is a `Configuration` property, so it belongs to the
client constructor's blocking behavior; the provider no longer reuses it
to bound `InitializeAsync`.
- `InitializeAsync` again waits for the client to become ready or to
fail permanently, with no timeout of its own; callers bound the wait by
choosing whether to await `SetProviderAsync`.
- README feature matrix and asynchronous-initialization section updated
to describe the restored behavior.

**Requirements**

- [x] I have added test coverage for new or changed functionality (tests
added by the reverted PRs are removed)
- [x] I have followed the repository's [pull request submission
guidelines](../blob/main/CONTRIBUTING.md#submitting-pull-requests)
- [ ] I have validated my changes against all supported platform
versions

<details>
<summary>Implementation details</summary>

**Related issues**

Reverts #60 ("Stop waiting for initialization after the configured start
wait time", released in 2.2.0) and #66 ("Resolve initialization
immediately when a start wait time was used", pending release in 2.3.1).

**Describe the solution you've provided**

`git revert` of both commits, so `Provider.cs` is byte-identical to its
state at ed29935 (immediately before #60): the internal `startWait`
constructor parameter, the `StartWait(config)` helper,
`FailInitializationIfNotReady`, and the `_initLock` around the `Valid`
status transition are all gone. The README matrix row for Initialization
is rewritten rather than restored verbatim, because the text #64 added
described the #60 behavior.

The rationale: `StartWaitTime` lives on `Configuration`, not on the
provider constructor, and the LaunchDarkly client constructor has
already consumed it before OpenFeature ever calls `InitializeAsync`.
Deriving an OpenFeature initialization deadline from it made the same
value mean two different things, and made a non-awaited
`SetProviderAsync` put the provider into `ERROR` for a merely slow
start.

**Describe alternatives you've considered**

Keeping #66 and only adjusting the messaging, or exposing an explicit
provider-level initialization timeout parameter. Neither was pursued:
the requested outcome is the original behavior, where the caller
controls how long to wait by awaiting `SetProviderAsync` or not.

**Additional context**

Behavior after this revert, per registration style:

- `SetProviderAsync(provider)` not awaited: initialization runs in the
background and waits for readiness; a `PROVIDER_READY` event is emitted
whenever the data source becomes valid.
- `SetProviderAsync(provider)` awaited: waits until the data source
becomes valid or permanently fails. With a positive `StartWaitTime` the
client constructor has already blocked for that long, so the remaining
wait is unbounded — use `StartWaitTime` to bound constructor blocking
and the OpenFeature `PROVIDER_ERROR`/`PROVIDER_READY` events to observe
later state.

`dotnet test` passes on `net8.0` (68 tests); `net471` and `net6.0`
runtimes are unavailable in this environment and are covered by CI.
</details>


Link to Devin session:
https://app.devin.ai/sessions/34fc74bc093b4c6680d2fddef4a4679b
Open in Devin Desktop:
https://app.devin.ai/desktop/session/34fc74bc093b4c6680d2fddef4a4679b?variant=devin
Requested by: @kinyoklion

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Overview**
> Reverts the 2.2.x behavior where **`StartWaitTime` also capped
OpenFeature `InitializeAsync`**. **`InitializeAsync` again waits until
the LaunchDarkly data source is ready or permanently fails**, with no
provider-level timeout; **`StartWaitTime` only affects blocking in the
`LdClient` constructor**.
> 
> The provider drops the internal start-wait plumbing
(`FailInitializationIfNotReady`, `StartWait(config)`, and the extra lock
on the `Valid` status path). README **Initialization** and
**Asynchronous initialization** text is updated to match. Tests that
asserted init timeout / late-ready after timeout are removed.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
bd5d310. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

Co-authored-by: Devin AI <devin-ai-integration[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants