Skip to content

feat: Add a shared file data reloader, poller, and watcher - #361

Draft
kinyoklion wants to merge 1 commit into
feat/overridesfrom
rlamb/overrides-dotnet-filedata-reloader
Draft

kinyoklion wants to merge 1 commit into
feat/overridesfrom
rlamb/overrides-dotnet-filedata-reloader

Conversation

@kinyoklion

@kinyoklion kinyoklion commented Sep 25, 2026 •

Copy link
Copy Markdown
Member

Summary

This is the first of the file-based flag overrides changes for the server SDK, as defined by the OVERRIDE specification. The override source that a later change adds needs file reading code with the reliability the specification requires of a source that operators edit during an incident: a reload that keeps the last good data when a file is unreadable or malformed, a retry after such a failure that does not wait for another change notification, coalescing of the burst of notifications that one edit produces, a file that does not exist yet contributing no data, and a change detector that does not depend on notification delivery.

The new Internal/FileLoading namespace holds that code. It is purely additive: nothing in the SDK uses it yet, and the existing file data source keeps its current behavior.

  • FileDataParser parses the file data document format (flags, flagValues, segments) into a FileDataDocument, keeping each entry's own version, with the same optional alternate parser for non-JSON content as the file data source. MakeOffFlagWithValue expands a flagValues entry into a flag that is off and serves its single value, which is the form the override source uses.
  • FileDataMerger combines documents in configured order with Fail or Ignore duplicate keys handling and reports how many entries it kept from each document.
  • FileDataReloader owns the reload cycle: it serializes reloads, debounces change signals with a settle window that each signal extends, retains the last good result on failure by not applying anything, retries a failed reload after a bounded delay, reports an identical repeated failure once, skips a reload whose raw contents are unchanged, and optionally treats a missing file as a file with no content. Dispose never waits for an in-flight reload.
  • FileDataPoller detects changes by examining each file's modification time, size, and existence on a fixed interval.
  • FileDataWatcher detects changes through FileSystemWatcher on each file's directory, so a file that appears later or is deleted is reported.

FileDataSource, FlagFileParser, and the file data source builder are unchanged, and their existing tests are unchanged. FileDataSourceExistingBehaviorTest adds tests that pin behavior of the file data source that its existing tests did not assert directly, so that later changes to the shared code cannot alter it: every successful load is applied even when the content is unchanged, the 600 ms retry delay and its warning on every failed attempt, the log messages and levels for a failed load, a path in a missing directory being a failure even with SkipMissingPaths, and a deleted file producing no reload.

Every new component has unit tests, including the debounce settle window, retry without further signals, last-good retention and recovery, serialized reloads, and non-blocking dispose. No public API changes.

Adds the Internal/FileLoading namespace with the file reading code that
the flag overrides feature needs: a document parser and merger that keep
each entry's own version and report per-document counts, a reloader that
serializes reloads, debounces change signals, retains the last good
result on failure, retries after a bounded delay, reports an identical
repeated failure once, and skips unchanged content, a stat-based poller,
and a directory watcher that handles files that do not exist yet.

The existing file data source keeps its current behavior and does not use
the shared code. Tests that pin that behavior are added so later changes
to the shared code cannot alter it.
@kinyoklion
kinyoklion force-pushed the rlamb/overrides-dotnet-filedata-reloader branch from 883fd4b to 353e748 Compare September 28, 2026 20:39

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant