feat: Add a start wait timeout for initialization - #59
Conversation
Co-Authored-By: rlamb@launchdarkly.com <4955475+kinyoklion@users.noreply.github.com>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
|
@cursor review |
Co-Authored-By: rlamb@launchdarkly.com <4955475+kinyoklion@users.noreply.github.com>
Co-Authored-By: rlamb@launchdarkly.com <4955475+kinyoklion@users.noreply.github.com>
Co-Authored-By: rlamb@launchdarkly.com <4955475+kinyoklion@users.noreply.github.com>
Co-Authored-By: rlamb@launchdarkly.com <4955475+kinyoklion@users.noreply.github.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
Reviewed by Cursor Bugbot for commit 69390f7. Configure here.
| ready_event.wait() | ||
| # With a start wait the client constructor has already waited, so the outcome is whatever it is now. | ||
| if self.__start_wait <= 0: | ||
| ready_event.wait() |
There was a problem hiding this comment.
Timeout drops later ready events
Medium Severity
When start_wait expires, initialize raises ProviderNotReadyError before attaching the data-source and flag listeners. A later LaunchDarkly connection never emits PROVIDER_READY, so OpenFeature stays in ERROR and configuration-change events are also dropped.
Reviewed by Cursor Bugbot for commit 69390f7. Configure here.
There was a problem hiding this comment.
This is correct, and it contradicts a bullet in the description above (now fixed): the raise happens before the status and flag-change listeners are attached, so a provider whose start wait lapses stays silent — no PROVIDER_READY when the connection later succeeds, and no configuration-changed events either. It isn't new to this PR (the same was true of the pre-existing is_initialized() failure path), but a start wait makes it reachable from mere slowness rather than only from a permanent failure.
Not changing it here, since it's the same open question as on openfeature-java-server#61: whether a lapsed start wait is terminal for the provider or just a failed initialization it can recover from. Attaching the listeners before the raise is the fix if it's the latter, and it should be decided the same way in both languages.
🤖 I have created a release *beep* *boop* --- ## [0.8.0](0.7.0...0.8.0) (2026-08-31) ### Features * Add a start wait timeout for initialization ([#59](#59)) ([c8708fd](c8708fd)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Overview** > **Release 0.8.0** — mechanical version bump from **0.7.0** across the release manifest, `pyproject.toml`, `ld_openfeature/version.py`, and Sphinx `docs/conf.py`, plus a new **CHANGELOG** section dated 2026-08-31. > > The changelog records one user-facing item for this tag: **configurable start wait timeout for provider initialization** ([#59]), which was already landed on `main` and is not part of this diff. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 7537919. 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: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>


Adds a
start_waitparameter toLaunchDarklyProvider, defaulting to the LaunchDarkly SDK's five seconds.Closes #55.
LDClient(config, start_wait)and bounds the whole of initialization once: with a positive valueinitializereports the outcome the constructor already waited for rather than waiting again, so a five second start wait cannot become a ten second wait forset_provider_and_wait.initializethen waits without a deadline for the data source to become valid or to fail permanently.Implementation details
Requirements
Related issues
#55, and the matching Java change in openfeature-java-server#61. Related spec change: sdk-specs#257.
Describe the solution you've provided
mainhas since merged #56, #57 and #58; those are merged into this branch, sostart_waitcomposes with the wrapper information now passed toLDClient, and a failed initialization raisesProviderNotReadyErrorrather than a fatal error.Describe alternatives you've considered
Waiting on the ready event for
start_waitseconds insideinitializeas well: that doubled the effective wait, since the client constructor had already waited the same amount.Additional context
Testing:
make test(84 passed) andmake lint. Tests cover the default matching the SDK default and initialization failing without waiting a second time; the timing assertion fails rather than hanging CI if the double wait comes back.Link to Devin session: https://app.devin.ai/sessions/38a6eaf69fcf41109e136a1d0fe5e899
Open in Devin Desktop: https://app.devin.ai/desktop/session/38a6eaf69fcf41109e136a1d0fe5e899?variant=devin
Requested by: @kinyoklion
Note
Overview
Adds an optional
start_waitargument toLaunchDarklyProvider(default 5 seconds, aligned withLDClient) so initialization can be bounded instead of waiting indefinitely.Positive
start_wait: the constructor blocks up to that limit while the client connects;initializedoes not wait again on the ready event, so total wait time is not doubled (e.g. forset_provider_and_wait). If the client is not ready in time,initializeraisesProviderNotReadyError.start_waitof 0: the constructor does not block;initializewaits without a deadline until the data source becomes valid or fails permanently (previous behavior).README marks Initialization as fully supported and documents
start_wait. Tests cover the default passed toLDClientand that a positivestart_waitdoes not add a second long wait ininitialize(viaNeverReadyDataSource).Reviewed by Cursor Bugbot for commit 69390f7. Bugbot is set up for automated code reviews on this repo. Configure here.