Commit 15014c1
fix: Do not report a permanent data source failure as fatal (#52)
A permanent data source failure no longer puts the provider into the
OpenFeature `FATAL` state, so the OpenFeature client keeps evaluating
against the flag data the LaunchDarkly client already has.
- `DataSourceState.OFF` now emits `ErrorCode.GENERAL` instead of
`ErrorCode.PROVIDER_FATAL`
- Matches the Java provider, which reports this as `ERROR`
- Relates to #49
**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
<details>
<summary>Implementation details</summary>
**Related issues**
#49 — during an outage, a `401` on an already-established stream took
the data source to `OFF` and OpenFeature evaluations started returning
call-site defaults even though the LaunchDarkly client still had valid
flag data.
**Describe the solution you've provided**
The OpenFeature Python SDK short-circuits evaluation when the provider
status is `FATAL`:
```python
if status == ProviderStatus.FATAL:
return ProviderFatalError()
```
That means the provider is never asked to evaluate and the call-site
default is returned. `PROVIDER_FATAL` is what moves the provider into
that status, so reporting a permanent data source failure that way
discards flag data the LaunchDarkly client can still serve.
`ErrorCode.GENERAL` keeps the provider in `ERROR`, which still surfaces
the failure through provider events and `get_provider_status()` while
leaving evaluation intact.
**Describe alternatives you've considered**
Leaving the state fatal only when the client never initialized was
considered. It adds state tracking to the provider for little benefit: a
client that never initialized has no flag data, so evaluations already
fall back to defaults with a `PROVIDER_NOT_READY`/`ERROR` reason, and
the `ERROR` status carries the same signal to anything watching provider
events.
**Testing**
Added
`test_evaluations_continue_after_the_data_source_permanently_fails`,
backed by a new `InitializedThenFailingDataSource` fixture that
initializes with flag data, goes `VALID`, then transitions to `OFF` with
a `401`. The test asserts the provider status is `ERROR` and that the
cached flag still evaluates to its real value rather than the call-site
default.
</details>
Link to Devin session:
https://app.devin.ai/sessions/0c452d209ec54b068ba120b4c92b8f6c
Requested by: @kinyoklion
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Overview**
> Stops treating a permanent data source failure (`DataSourceState.OFF`)
as OpenFeature `PROVIDER_FATAL`, so evaluations keep using cached
LaunchDarkly flag data instead of being short-circuited to call-site
defaults.
>
> `__handle_data_source_status` now emits `ErrorCode.GENERAL`, leaving
the provider in `ERROR` while still surfacing the failure. A new test
initializes flags, then fails the data source with a 401, and asserts
status is `ERROR` and the cached flag still evaluates correctly.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
e0fea34. 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>1 parent 82de51d commit 15014c1
3 files changed
Lines changed: 62 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
41 | 41 | | |
42 | 42 | | |
43 | 43 | | |
44 | | - | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
45 | 48 | | |
46 | 49 | | |
47 | 50 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
74 | 74 | | |
75 | 75 | | |
76 | 76 | | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
77 | 111 | | |
78 | 112 | | |
79 | 113 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
| 14 | + | |
14 | 15 | | |
15 | 16 | | |
16 | 17 | | |
17 | | - | |
| 18 | + | |
18 | 19 | | |
19 | 20 | | |
20 | 21 | | |
| |||
232 | 233 | | |
233 | 234 | | |
234 | 235 | | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
235 | 258 | | |
236 | 259 | | |
237 | 260 | | |
| |||
0 commit comments