Documentation
¶
Overview ¶
Package filedata contains the file reading, parsing, and merging logic shared by the components that load flag and segment data from local files.
Index ¶
Constants ¶
const ( // DefaultDebounceDelay is a settle window long enough to coalesce the burst of change // notifications produced by a single file edit, and short enough to stay responsive. DefaultDebounceDelay = 100 * time.Millisecond // DefaultRetryDelay bounds how long a failed reload can go uncorrected when no further // change notification arrives, for example when the failure came from reading a file // mid-write. Reading a local file is cheap, so this can be short. DefaultRetryDelay = time.Second )
Variables ¶
This section is empty.
Functions ¶
func AbsFilePaths ¶
AbsFilePaths converts each of the given paths to an absolute path.
func MakeFlagWithValue ¶
func MakeFlagWithValue(key string, v interface{}) *ldmodel.FeatureFlag
MakeFlagWithValue expands a flag-key-to-value entry into a full flag definition that returns the given value for every context.
Types ¶
type Document ¶
type Document struct {
Flags *map[string]ldmodel.FeatureFlag
FlagValues *map[string]ldvalue.Value
Segments *map[string]ldmodel.Segment
}
Document is the parsed form of a single data file. A document may contain full flag definitions, simplified flag-key-to-value entries, and segment definitions.
type DocumentSummary ¶ added in v7.18.0
DocumentSummary counts the entries the merge kept from one document.
type DuplicateKeysHandling ¶
type DuplicateKeysHandling string
DuplicateKeysHandling determines what happens when the same flag or segment key appears in more than one document.
The values match the public option types in the packages that expose this behavior, so those types can be converted to this one directly.
const ( // DuplicateKeysFail means a duplicated key causes the merge to fail. DuplicateKeysFail DuplicateKeysHandling = "fail" // DuplicateKeysIgnoreAllButFirst means only the first occurrence of a duplicated key is // used, in the order the documents were given. DuplicateKeysIgnoreAllButFirst DuplicateKeysHandling = "ignore" )
type FileSummary ¶ added in v7.18.0
type FileSummary struct {
Path string
// Present is false when the file does not exist and missing files are skipped.
Present bool
Flags int
Segments int
}
FileSummary describes one configured file after a reload.
type MergeResult ¶
type MergeResult struct {
Flags []ldstoretypes.KeyedItemDescriptor
Segments []ldstoretypes.KeyedItemDescriptor
// Documents holds, for each input document in order, the number of entries the merge kept
// from it. An entry dropped by the duplicate-key handling is not counted.
Documents []DocumentSummary
// Files is set by the Reloader. It describes each configured file in order.
Files []FileSummary
}
MergeResult holds the merged items from one or more documents. Item values are *ldmodel.FeatureFlag or *ldmodel.Segment.
Ordering is deterministic at document granularity only: all of one document's items precede the next document's, matching the order the documents were given, but the relative order of items within a single document is unspecified. Consumers key items by their Key and must not rely on within-document ordering.
func Merge ¶
func Merge(duplicateKeysHandling DuplicateKeysHandling, docs ...Document) (MergeResult, error)
Merge combines the items of the given documents, expanding flag-value entries into full flag definitions and applying the given duplicate-key handling. An unrecognized DuplicateKeysHandling value behaves as DuplicateKeysFail.
type Poller ¶ added in v7.18.0
type Poller struct {
// contains filtered or unexported fields
}
Poller detects changes to a set of files by examining them on a fixed interval. Use it where file system change notifications are not available or not reliable, alone or together with them. A change to the modification time or the size of any file invokes the onChange callback. A file that appears or disappears is also a change. A file that os.Stat cannot examine counts as absent.
The poller samples the files once per interval and compares only modification time and size. A rewrite that keeps both values is not detected.
Detection is generous. onChange can run for a change that does not alter the effective data. Feed it into a Reloader, whose debouncing and skip-unchanged handling absorb the excess.
func NewPoller ¶ added in v7.18.0
NewPoller creates a started Poller. It examines the files once before it returns, so only later changes invoke onChange. Call Close to stop it.
func (*Poller) Close ¶ added in v7.18.0
func (p *Poller) Close()
Close stops the poller. It does not wait for an examination or a callback that is in progress. A file system that does not respond must not block shutdown. As a result, onChange can run one more time shortly after Close returns. Consumers tolerate a late call, as they do for a late reload.
type ReadError ¶ added in v7.18.0
ReadError indicates that one of the source files could not be read or parsed. It distinguishes a per-file failure from a failure to merge the files' contents.
type Reloader ¶ added in v7.18.0
type Reloader struct {
// contains filtered or unexported fields
}
Reloader owns the reload cycle for a set of data files: it serializes reloads, debounces change signals, retains the last good result on failure (by not calling Apply), retries after failures, and skips no-op applications.
func NewReloader ¶ added in v7.18.0
func NewReloader(cfg ReloaderConfig) *Reloader
NewReloader creates a Reloader. The caller should perform the initial load with ReloadNow, route change signals to Trigger, and call Close when finished.
The worker goroutine starts on the first ReloadNow or Trigger call rather than here: a Reloader can be constructed by a component whose lifecycle never uses it (a file data source built as a one-shot initializer, whose interface has no Close), and construction alone must not leak a goroutine.
func (*Reloader) Close ¶ added in v7.18.0
func (r *Reloader) Close()
Close stops the reloader. It does not wait for a reload that is already in progress -- one wedged in a blocking file read (an unresponsive network mount, for example) must not be able to wedge shutdown -- so such a reload may still deliver its result through Apply or OnError shortly after Close returns; consumers must tolerate that, as they always have for late reloads. A reload that has not yet reached its callbacks when Close is called will not invoke them.
type ReloaderConfig ¶ added in v7.18.0
type ReloaderConfig struct {
// Paths is the list of files to load, already resolved to absolute paths. The order is
// significant: it determines which file wins under the duplicate-key handling.
Paths []string
// DuplicateKeysHandling determines what happens when the same key appears in more than
// one file.
DuplicateKeysHandling DuplicateKeysHandling
// SkipMissingPaths, when true, treats a configured file that does not exist as a file
// with no content. The reload succeeds with the data of the files that exist. When
// false, a missing file fails the reload like any other read error.
SkipMissingPaths bool
// Loggers receives log output about reloads and failures.
Loggers ldlog.Loggers
// Apply is invoked with each successfully merged result. Calls are serialized on the
// reloader's own goroutine (or, for ReloadNow, under the same lock), so implementations
// do not need their own synchronization against other reloads. Apply and OnError must
// not call back into Close.
Apply func(MergeResult)
// OnError is invoked when a reload fails, once per distinct failure: with automatic
// retries, repeats of an identical failure do not re-invoke it (a success re-arms it).
// The error is a *ReadError when a file could not be read or parsed, or a merge error
// otherwise. The reloader logs failures itself, so implementations only need to update
// their own state.
OnError func(err error)
// DebounceDelay is how long to wait after a Trigger call for further calls to settle
// before reloading, coalescing bursts of change notifications into one reload. If zero
// or negative, each Trigger reloads immediately.
DebounceDelay time.Duration
// RetryDelay is how long to wait after a failed reload before automatically retrying,
// so that a failure observed while a file was being rewritten recovers even if no
// further change notification arrives. If zero or negative, there is no automatic
// retry.
RetryDelay time.Duration
// SkipUnchanged, if true, suppresses the Apply call when the files' raw contents are
// byte-identical to the last successfully applied contents.
SkipUnchanged bool
}
ReloaderConfig configures a Reloader.