filedata

package
v7.19.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 7, 2026 License: Apache-2.0 Imports: 18 Imported by: 0

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

View Source
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

func AbsFilePaths(paths []string) ([]string, error)

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.

func ReadFile

func ReadFile(path string) (Document, error)

ReadFile reads and parses a single data file, which may be in JSON or YAML format.

type DocumentSummary added in v7.18.0

type DocumentSummary struct {
	Flags    int
	Segments int
}

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

func NewPoller(paths []string, interval time.Duration, onChange func()) *Poller

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

type ReadError struct {
	Err  error
	Path string
}

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.

func (*ReadError) Error added in v7.18.0

func (e *ReadError) Error() string

func (*ReadError) Unwrap added in v7.18.0

func (e *ReadError) Unwrap() error

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.

func (*Reloader) ReloadNow added in v7.18.0

func (r *Reloader) ReloadNow()

ReloadNow synchronously loads the files and applies the result (or reports the failure). It is used for the initial load; a failure here schedules the same automatic retry as a failed triggered reload.

func (*Reloader) Trigger added in v7.18.0

func (r *Reloader) Trigger()

Trigger signals that the files may have changed and a reload should happen after the debounce delay. It never blocks; signals arriving while a reload is already pending are coalesced.

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL