Skip to content

feat!: Add a start wait time option for initialization - #66

Draft
kinyoklion wants to merge 3 commits into
mainfrom
devin/1789570463-java-start-wait
Draft

kinyoklion wants to merge 3 commits into
mainfrom
devin/1789570463-java-start-wait

Conversation

@kinyoklion

@kinyoklion kinyoklion commented Sep 16, 2026 •

Copy link
Copy Markdown
Member

Requirements

  • I have added test coverage for new or changed functionality
  • I have followed the repository's pull request submission guidelines
  • I have validated my changes against all supported platform versions

Related issues

Fixes #58.

Describe the solution you've provided

Adds Provider(String sdkKey, LDConfig config, Duration startWait) so an application can bound, or deliberately opt out of, waiting for initialization, matching the OpenFeature provider spec (OFP) requirements for start wait behavior:

  • a positive Duration is applied by the LaunchDarkly client constructor, and initialize then reports whether the client became ready without waiting a second time
  • Duration.ZERO waits nowhere; initialize fails unless the client is already ready, and the application learns when it becomes usable from provider events
  • null requests indefinite waiting: nothing is waited for during construction and initialize blocks until the data source becomes valid or fails permanently

The existing constructors keep honouring LDConfig.Builder.startWait(...) and no longer wait again in initialize, so a configured start wait is the only bound on initialization instead of being followed by an unbounded wait. The README feature matrix row and initialization section describe the new behavior.

Implementation details

initialize still registers data source and flag change listeners and evaluates the current data source status. Only the indefinite mode leaves the completion future pending; every other mode completes it with the outcome that is already known, so initialize returns promptly. Status reporting after a failed initialization is unchanged.

Describe alternatives you've considered

Keeping the existing indefinite wait and adding a timeout parameter interpreted only inside initialize would double-wait when LDConfig.startWait is also set, and would not match OFP, which treats the start wait as a bound over construction plus initialization.

Additional context

Sibling changes for the same OFP requirement: launchdarkly/openfeature-python-server#64, launchdarkly/openfeature-ruby-server#36, launchdarkly/openfeature-dotnet-server#71, and launchdarkly/js-core#2024.

Verified with ./gradlew test (all tests pass, including new coverage for positive, zero, and indefinite start wait).

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

SDK-3285

Fixes #58

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 devin-ai-integration Bot changed the title feat: Add a start wait time option for initialization feat!: Add a start wait time option for initialization Sep 16, 2026
Co-Authored-By: rlamb@launchdarkly.com <4955475+kinyoklion@users.noreply.github.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor

@cursor review

Co-Authored-By: rlamb@launchdarkly.com <4955475+kinyoklion@users.noreply.github.com>
kinyoklion added a commit to launchdarkly/js-core that referenced this pull request Oct 9, 2026
Gives the OpenFeature providers the initialization waiting values the
OpenFeature provider spec (OFP) requires, which the numeric-only
`initTimeoutSeconds` could not express.

- `initTimeoutSeconds: 'forever'` waits indefinitely for the
LaunchDarkly client
- `initTimeoutSeconds: 0` waits nowhere and fails initialization unless
the client is already ready, so readiness is observed through provider
events
- A positive timeout behaves as before, and the default is still 10
seconds
- Node provider README feature matrix row updated for the new values

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

**Requirements**

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

**Related issues**

OFP requirement 4.3.4 requires a value distinct from any duration to
request waiting indefinitely, and 4.3.6 requires a zero wait to wait
nowhere and fail initialization. Sibling changes for the same
requirement: launchdarkly/openfeature-java-server#66,
launchdarkly/openfeature-python-server#64,
launchdarkly/openfeature-dotnet-server#71,
launchdarkly/openfeature-ruby-server#36.

**Describe the solution you've provided**

`BaseProviderConfig.initTimeoutSeconds` and the Node provider's
constructor parameter are now `number | 'forever'`, and zero is no
longer coalesced into the default, since `??` only replaces `undefined`.
`waitForInitialization` treats a falsy timeout as no timeout, so zero
cannot be passed through: initialization races the pending
initialization promise against an immediately rejected one, which
succeeds only when the client is already ready.

The Cloudflare provider is unaffected because it evaluates from a KV
namespace and has no data source to wait for.

**Describe alternatives you've considered**

`number | null` was used initially for the indefinite case; `'forever'`
reads better at the call site and matches the repository's preference
for string unions. Adding `initialized()` to the client contract would
let the zero case be checked directly, but that is a breaking change to
a published interface for behavior the existing promise already
expresses.

**Additional context**

Verified with `yarn workspace @launchdarkly/openfeature-js-server-common
test` (82 tests), `yarn workspace @launchdarkly/openfeature-node-server
test` (29 tests), and lint, format and build checks for both packages.

</details>

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Overview**
> Extends **`initTimeoutSeconds`** on the shared
**`BaseOpenFeatureProvider`** and the Node **`LaunchDarklyProvider`** to
**`number | 'forever'`**, aligning initialization with the OpenFeature
provider spec.
> 
> **`'forever'`** calls **`waitForInitialization()`** with no timeout.
**`0`** no longer falls through to the 10-second default (only
**`undefined`** does); initialization races the client’s init promise
against an immediate failure so it succeeds only when the client is
already ready, otherwise it throws a clear error. Positive timeouts
behave as before (default **10** seconds).
> 
> The Node provider README initialization row documents the new values,
and unit tests cover indefinite wait, zero-timeout failure, and
zero-timeout success when already ready.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
87e9a23. 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 <158243242+devin-ai-integration[bot]@users.noreply.github.com>

This branch has not been deployed

No deployments
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.

Provider initialization can block indefinitely

1 participant