Repository navigation
feat: Add the file-based override source - #367
kinyoklion wants to merge 4 commits into
Conversation
86caaa5 to
9ddeb28
Compare
4011fef to
bf327fc
Compare
9ddeb28 to
75135db
Compare
bf327fc to
e30694a
Compare
75135db to
89329c5
Compare
e30694a to
4de98c7
Compare
|
bugbot review |
89329c5 to
403d56e
Compare
4de98c7 to
57ffcf0
Compare
403d56e to
b085719
Compare
57ffcf0 to
c3dbd2d
Compare
b085719 to
2b54c3e
Compare
c3dbd2d to
6973a4f
Compare
2b54c3e to
4ec85dc
Compare
6973a4f to
78d3e87
Compare
4ec85dc to
368f8fa
Compare
78d3e87 to
08c4cf0
Compare
368f8fa to
f12a5f6
Compare
08c4cf0 to
c9c756b
Compare
f12a5f6 to
6d2b453
Compare
c9c756b to
e0d0597
Compare
|
bugbot review |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 6bdec5e. Configure here.
| // A path listed more than once would make every entry of that file a duplicate of itself, so | ||
| // the repeats are dropped and the first occurrence keeps its place in the order. | ||
| var allPaths = _paths.Select(Path.GetFullPath).ToList(); | ||
| var paths = allPaths.Distinct().ToList(); |
There was a problem hiding this comment.
Duplicate paths missed on Windows
Low Severity
Path deduplication uses Distinct() with case-sensitive equality after Path.GetFullPath, which preserves input casing. On Windows the same file listed twice with different casing is kept as two paths, so default Fail handling treats every key as a duplicate of itself and the reload never applies.
Reviewed by Cursor Bugbot for commit 6bdec5e. Configure here.
Adds FileOverrides.Source() and FileOverrideSourceBuilder with FilePaths, DuplicateKeysHandling (Fail by default, or Ignore), ChangeDetection (Polling by default, or Watching), PollInterval (one second by default and at minimum), and Parser for non-JSON content. The source reads files in the file data document format, expands flagValues entries into flags that are off and serve their single value, merges the files in order, treats a missing file as contributing no overrides, keeps the last good overrides across a file that cannot be read or parsed with a logged failure and a retry, and logs the overrides in effect and what each file supplied at Info level on every applied change, as defined by the OVERRIDE specification.
… interval above the timer maximum The file override source sets up its change detector before it reads the files, so a change made during the initial load is reported. The builder rejects a polling interval longer than the timer supports when the client is created, instead of failing when the source starts.
…ntries as duplicate keys A path listed more than once would make every entry of that file a duplicate of itself: under the default fail handling the load failed, and under ignore the first listing won by accident. The builder now drops the repeats, keeps the first occurrence in its place in the order, and logs a warning once at build time. This is the behavior the Node SDK has.
6d2b453 to
4e21dce
Compare
6bdec5e to
40f4cd0
Compare


Summary
Adds the file-based override source, as defined by the OVERRIDE specification, on top of the shared file loading code and the override layer from the earlier changes in this series. The existing file data source keeps its current behavior: it does not use the shared code, and nothing in this change touches it.
Configuration:
FileOverrides.Source()returns aFileOverrideSourceBuilderthat is passed toDataSystemBuilder.Overrides(...). Its options areFilePaths(one or more files, in precedence order, required),DuplicateKeysHandling(Fail, the default, orIgnore, which keeps the first configured file's entry),ChangeDetection(Polling, the default, orWatching),PollInterval(one second by default and at minimum; a lower value is raised to the minimum with a warning), andParserfor non-JSON content such as YAML. Building a source with no file paths, or with an option outside its enumeration, throws, so the client constructor fails the same way it does for other invalid component configuration. A path listed more than once is logged at Warn and the repeats are ignored; the first occurrence keeps its place in the order. Every public member carries the note that flag overrides are currently experimental and subject to change.Behavior: the files use the file data source document format (
flags,flagValues,segments); aflagValuesentry expands to a flag that is on and serves its single value by fallthrough, so it evaluates with theFALLTHROUGHreason. The initial load runs inside the client constructor. Change detection is in place before the initial load, so a change made between the two is not missed. In watching mode a configured path that is a link to a file in another directory is detected only through the periodic directory check; polling, the default, follows the link directly. A configured file that does not exist contributes no overrides and produces no error log; creating it later adds its overrides and deleting it removes them. A file that exists but cannot be read or parsed, or a duplicate key underFail, fails that whole reload: the previously loaded overrides stay in effect, the failure is logged, and the source retries after a bounded delay and on the next change. Every applied change is logged at Info level with the overrides in effect and what each configured file supplied (for exampleFlag overrides in effect: 2 flags, 1 segment (/etc/ld/a.json: 2 flags, 1 segment; /etc/ld/b.json: absent)). Polling examines the files' modification time, size, and existence once per interval; watching uses file system notifications on each file's directory.YAML: the SDK does not bundle a YAML parser, following the existing file data source, so YAML files require the application to supply a parser through the
Parseroption. The specification asks for YAML support in the source itself; this is the deliberate deviation for the .NET SDK, and adding a YAML dependency to the SDK package is the alternative.Tests cover the builder validation and defaults, every file behavior above in both change detection modes, the Info log lines, and a client end-to-end scenario in which an operator adds, changes, and removes an override on a running client that never obtains LaunchDarkly data.
This PR is based on the branch of the server events change, which it depends on.
SDK-3248
Note
Overview
Adds an experimental file-based flag override integration so operators can force flag/segment values from local files via
DataSystemBuilder.Overrides(FileOverrides.Source().FilePaths(...)), without restarting the client.The public surface is
FileOverrides,FileOverrideSourceBuilder, andFileOverrideTypes(duplicate-key handling, polling vs watching, poll interval, optional custom parser for YAML).FileOverrideSourcemerges one or more file-data-format JSON files through sharedFileDataReloadermachinery, applies full snapshots to the override layer on startup and on change, keeps the last good overrides on parse/duplicate-key failures, and logs what is in effect per file. Docs onDataSystemBuilder.OverridesandIOverrideSourcenow point atFileOverrides.Tests cover builder validation, reload/merge/missing-file behavior in both detection modes, and end-to-end
LdClientevaluations withOverrideAffected.Reviewed by Cursor Bugbot for commit 6bdec5e. Bugbot is set up for automated code reviews on this repo. Configure here.