You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 8bff7b3
Browse filesBrowse the repository at this point in the historyBrowse files
fix!: Use None rather than zero for indefinite initialization waiting (#64)
Aligns `start_wait` with the OpenFeature provider spec (OFP), which
requires a distinct non-duration value to request indefinite
initialization waiting.
- `start_wait=None` now requests an indefinite wait: the constructor
does not block and `initialize` waits until the data source becomes
valid or fails permanently.
- `start_wait=0` no longer waits indefinitely; it waits nowhere, so
`initialize` reports a failed initialization unless the client is
already ready, and readiness is observed through provider events.
- Positive values are unchanged: the constructor bounds the wait and
`initialize` returns immediately with whatever the outcome is.
- Breaking for anyone relying on `0` meaning "wait forever".
**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**
None.
<details>
<summary>Implementation details</summary>
OFP requires that a positive start wait bound total construction plus
initialization, that zero wait nowhere, and that indefinite waiting
avoid construction-time blocking and instead wait during `initialize`.
Previously zero was overloaded to mean indefinite, leaving no way to
express "no waiting at all".
`None` is now passed to `LDClient` as a zero construction wait, with the
waiting performed in `initialize` against the data source status
listener.
Testing: `make test` (88 tests) and `make lint` (mypy) pass. New tests
cover the zero and indefinite cases, including that the constructor does
not block when `None` is given.
</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
[SDK-3285](https://launchdarkly.atlassian.net/browse/SDK-3285)
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Overview**
> **Breaking change:** `start_wait` now matches the OpenFeature provider
contract instead of overloading `0` for “wait forever.”
>
> `start_wait=None` means indefinite waiting only inside `initialize`
(constructor passes `0` to `LDClient` so it does not block).
`start_wait=0` means no waiting anywhere—`initialize` fails immediately
unless the client is already ready, and later readiness is surfaced via
provider events. Positive values are unchanged.
>
> Provider lifecycle updates track `ProviderStatus`, register
data-source listeners before the readiness check, suppress duplicate
events during initialization, and still emit `PROVIDER_READY` if the
data source becomes valid after a failed init. README marks
initialization fully supported; tests add `DelayedReadyDataSource` and
cases for zero vs `None` and post-failure ready events.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
9dc4c47. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[SDK-3285]:
https://launchdarkly.atlassian.net/browse/SDK-3285?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
---------
Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Copy file name to clipboardExpand all lines: README.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -39,7 +39,7 @@ This matrix mirrors the [feature matrix of the OpenFeature SDK for Python](https
39
39
| ✅ | Domains | Domains bind clients to providers in the OpenFeature SDK; a separate provider instance may be registered per domain. |
40
40
| ✅ | Eventing | LaunchDarkly data source status changes are emitted as `PROVIDER_READY`, `PROVIDER_STALE` and `PROVIDER_ERROR`, and only when the status changes; flag changes as `PROVIDER_CONFIGURATION_CHANGED` with the changed flag key. |
41
41
| ✅ | Tracking |`track` sends a LaunchDarkly custom event for the evaluation context, with the tracking event value and remaining details attached. |
42
-
|⚠️| Initialization |`initialize` reports whether the LaunchDarkly client became ready. The optional `start_wait` parameter bounds initialization; zero applies no timeout and waits until the data source becomes valid or permanently fails. Since LaunchDarkly Python SDK 9.18.0 a rejected SDK key is retried rather than failing permanently, so zero can wait indefinitely. Provider gap: zero should not wait, [#64](https://github.com/launchdarkly/openfeature-python-server/pull/64).|
42
+
|✅| Initialization |`initialize` reports whether the LaunchDarkly client became ready. The optional `start_wait` parameter bounds initialization; `None`waits until the data source becomes valid or permanently fails. Since LaunchDarkly Python SDK 9.18.0 a rejected SDK key is retried rather than failing permanently, so `None` can wait indefinitely. |
43
43
| ✅ | Shutdown |`shutdown` closes the LaunchDarkly client; a closed client cannot be restarted, so a new provider instance is required afterward. |
44
44
| ✅ | Transaction Context Propagation | Provided by the OpenFeature SDK, which merges the transaction context into the evaluation context before the provider is called; no provider support is required. |
45
45
| ✅ | Extending | The underlying LaunchDarkly client is available through the `client` property. |
# Refer to OpenFeature documentation for getting a client and performing evaluations.
71
71
```
72
72
73
-
The optional `start_wait` parameter is the number of seconds to wait for a successful connection to LaunchDarkly, matching the same parameter of the LaunchDarkly SDK's `LDClient`, and defaulting to the same five seconds. A positive value bounds the whole of initialization: the provider constructor blocks for up to that long, and OpenFeature initialization then completes immediately, reporting a failed initialization if the client did not become ready in time. Zero does not block the constructor at all, and initialization then waits without a deadline for the data source to become valid or to fail permanently. Since LaunchDarkly Python SDK 9.18.0 a rejected SDK key is retried rather than treated as a permanent failure, so with zero, initialization does not complete while the key is rejected.
73
+
The optional `start_wait` parameter is the number of seconds to wait for a successful connection to LaunchDarkly, matching the same parameter of the LaunchDarkly SDK's `LDClient`, and defaulting to the same five seconds. A positive value bounds the whole of initialization: the provider constructor blocks for up to that long, and OpenFeature initialization then completes immediately, reporting a failed initialization if the client did not become ready in time. Zero waits nowhere, so initialization fails unless the client is already ready, and the application learns when the client becomes usable from provider events. `None` requests waiting indefinitely: the constructor does not block, and initialization waits without a deadline for the data source to become valid or to fail permanently. Since LaunchDarkly Python SDK 9.18.0 a rejected SDK key is retried rather than treated as a permanent failure, so with `None`, initialization does not complete while the key is rejected.
74
74
75
75
`api.set_provider` registers the provider without waiting for it to initialize, so the first evaluations may use fallback values while the LaunchDarkly client is still connecting. Use `api.set_provider_and_wait` instead when the application needs registration to block until initialization has succeeded or failed.
0 commit comments