Skip to content

Commit ff28e11

Browse files
Promote Unreleased to 0.9.0 (#163)
1 parent 30b75a2 commit ff28e11

1 file changed

Lines changed: 35 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [0.9.0] — 2026-05-13
11+
1012
### Added
1113

14+
- **Lifecycle and concurrency test coverage for `OptimizelyFeatureProvider`.** `OptimizelyProviderLifecycleSpec` covers
15+
double-initialize, double-shutdown, shutdown-before-initialize, evaluations before init / after shutdown, the full
16+
NOT_READY → READY → NOT_READY transition, NOT_READY → ERROR on failed init, and concurrent `initialize` from N
17+
threads converging on READY. `OptimizelyProviderConcurrencySpec` stress-tests 1000 parallel boolean evaluations and
18+
500 mixed-type evaluations racing init and shutdown — surfacing torn reads, NPEs, or deadlocks if present. (#158)
1219
- **Provider initialization hardening.** All `FeatureFlags.fromProvider*` factories accept a new `initTimeout` (default
1320
30 s). Sync init blocks no longer than that bound; async init transitions `ProviderStatus` to `Fatal` if the provider
1421
hasn't become ready in time. The sync path also verifies the provider's `getState()` after `setProviderAndWait`
@@ -64,6 +71,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6471
validated `make` / `layer` factories. The throwing factories remain for backwards compatibility but will be removed
6572
in a later major release.
6673

74+
### Fixed
75+
76+
- **Optimizely `PROVIDER_CONFIGURATION_CHANGED` events now reach OpenFeature `Client` listeners on every datafile
77+
update, not just the initial load.** `HttpProjectConfigManager` and the `Optimizely` client each construct their own
78+
`NotificationCenter` by default; without sharing, the manager fires `UpdateConfigNotification` on its private centre
79+
while handlers registered through `Optimizely.addUpdateConfigNotificationHandler` (the API our provider's
80+
`initialize` uses) live on the client's centre. `OptimizelyProvider.buildClient` now allocates one
81+
`NotificationCenter` and passes it to both builders. Initial loads worked already because
82+
`OptimizelyFeatureProvider.initialize` polls `optimizely.isValid` directly to count down its init latch, so the bug
83+
only manifested as silent event drops on revision changes after init. Two regression tests added (structural —
84+
`clientCtr eq mgrCtr`; behavioural — WireMock revision-bump + `Client.onProviderConfigurationChanged`). (#161)
85+
- **`OptimizelyFeatureProvider.decide()` no longer throws from a closed HTTP client after `shutdown()`.** Surfaced
86+
while writing the new lifecycle spec: `optimizely.isValid()` post-shutdown re-enters the polling HTTP client (closed
87+
by then) and Apache HttpClient throws an `IOException`. `decide` now checks the provider's own `stateRef` first
88+
(short-circuits with `PROVIDER_NOT_READY` for NOT_READY / ERROR states without touching the SDK) and wraps the
89+
defensive `isValid` probe in `Try`. Check order also changed: provider state precedes targeting-key validation,
90+
since a non-ready provider makes the caller's context irrelevant. (#158)
91+
- **`FeatureFlagsLive.setProvider` reliably leaves status at `Error` after a failed swap.** A race in the async
92+
`PROVIDER_READY` bridge could overwrite the explicit `Error` transition: a stale Ready event still pending on the
93+
OpenFeature SDK's emitter executor (cached thread pool, no ordering guarantee) would fire after `tapError` set
94+
`Error` and reset it to `Ready`. `setProvider` now stamps a `recentSwapFailureAt` timestamp before writing
95+
`statusRef.set(Error)`, and `readyHandler` switches from unconditional `set(Ready)` to a state-aware `update`:
96+
`NotReady`/`Stale``Ready` always, `Error``Ready` only if more than 500 ms have elapsed since the last failed
97+
swap. Eliminates the intermittent `FeatureFlagRegistrySpec.failed setProvider does not update providers map`
98+
failure observed in CI; 30/30 consecutive local runs after the fix. (#162)
99+
67100
## [0.8.0] — earlier
68101

69102
Prior versions tracked release-by-release in [GitHub Releases](https://github.com/EtaCassiopeia/zio-openfeature/releases).
@@ -90,5 +123,6 @@ promotes `[Unreleased]` to the new version section when a release tag is cut.
90123

91124
Internal refactors that don't change behaviour or surface area don't need a CHANGELOG entry. When in doubt: write one.
92125

93-
[Unreleased]: https://github.com/EtaCassiopeia/zio-openfeature/compare/v0.8.0...HEAD
126+
[Unreleased]: https://github.com/EtaCassiopeia/zio-openfeature/compare/v0.9.0...HEAD
127+
[0.9.0]: https://github.com/EtaCassiopeia/zio-openfeature/releases/tag/v0.9.0
94128
[0.8.0]: https://github.com/EtaCassiopeia/zio-openfeature/releases/tag/v0.8.0

0 commit comments

Comments
 (0)