Documentation
¶
Index ¶
- Constants
- func AddSource[T any](c *Configuration, src Source[T]) error
- func Get[T any](c *Configuration, name string) (*T, bool)
- func Lookup[T any](c *Configuration, name string) (*T, error)
- func MustGet[T any](c *Configuration, name string) *T
- type Configuration
- func (c *Configuration) AddSourceValue(src cf.ConfigSourceValue) error
- func (c *Configuration) GetDependencies() []string
- func (c *Configuration) GetInitOrderStage() cf.Stage
- func (c *Configuration) Init(ctx context.Context, fw *cf.CaerusFramework) error
- func (c *Configuration) JobRequests() ([]cf.JobRequest, error)
- func (c *Configuration) Name() string
- func (c *Configuration) ParseFlags(args []string) (rest []string, err error)
- func (c *Configuration) Reload(name string) error
- func (c *Configuration) ReloadAll() error
- func (c *Configuration) Shutdown(ctx context.Context) error
- func (c *Configuration) Sources() []string
- type Format
- type Option
- type Source
Constants ¶
const ComponentName = "configuration"
ComponentName is the framework component name for the configuration component. It is the identifier other components use in GetDependencies to require configuration.
Variables ¶
This section is empty.
Functions ¶
func AddSource ¶
func AddSource[T any](c *Configuration, src Source[T]) error
AddSource registers and loads a configuration source on the given component. The value is built immediately (fail-fast); the source is not registered on failure. Reloads never fail the process: a rejected reload keeps the previous value. AddSource is safe to call before or after Init.
Path and/or EnvPrefix must be set. Format is required when Path is set.
func Get ¶
func Get[T any](c *Configuration, name string) (*T, bool)
Get returns the current value of the named source on the given component, typed as *T. It reports false if the source does not exist or was registered with a different type. The returned pointer is atomically swapped on reload: readers always observe either the previous or the new value, never a partial write.
func Lookup ¶
func Lookup[T any](c *Configuration, name string) (*T, error)
Lookup returns the current value of the named source on the given component, typed as *T, or an error if it does not exist or was registered with a different type. Prefer Lookup (or Get) from Init and OnConfigReload so misconfiguration surfaces as error rather than panic.
func MustGet ¶
func MustGet[T any](c *Configuration, name string) *T
MustGet returns the current value of the named source on the given component, typed as *T, or panics if it does not exist or was registered with a different type. Prefer Lookup in Init/reload; MustGet is crash-fast sugar for main and tests where a missing source is a programmer error.
Types ¶
type Configuration ¶
type Configuration struct {
// contains filtered or unexported fields
}
Configuration is the caerus-framework-configuration component. It owns a set of per-component configuration sources: each is loaded exactly once, watched for changes, and swapped atomically on a validated reload.
func New ¶
func New(opts ...Option) *Configuration
New creates a configuration component. Add sources with AddSource (from any component's Init) and read the current value with Get/MustGet.
func (*Configuration) AddSourceValue ¶
func (c *Configuration) AddSourceValue(src cf.ConfigSourceValue) error
AddSourceValue registers a configuration source from its generic-free declaration (cf.ConfigSourceValue). It is the cycle-free entry point for core modules (logs, observability) that the configuration module imports: the framework hands them the component as cf.ConfigSourceAdder and they call this with their own declaration. Sample's dynamic type selects the concrete config struct and decoding, exactly as Source[T].T would.
func (*Configuration) GetDependencies ¶
func (c *Configuration) GetDependencies() []string
GetDependencies implements cf.Dependencies. The component logs through the framework logs component.
func (*Configuration) GetInitOrderStage ¶
func (c *Configuration) GetInitOrderStage() cf.Stage
GetInitOrderStage implements cf.CaerusComponent. Configuration runs in the second bootstrap stage, right after logs, so later components can read their config during Init.
func (*Configuration) Init ¶
func (c *Configuration) Init(ctx context.Context, fw *cf.CaerusFramework) error
Init implements cf.CaerusComponent. It starts the file watcher and the reload loop, and begins watching every source registered so far. Sources registered later (during other components' Init) are watched immediately.
After starting the watcher it notifies each source's owner with the already-loaded value. The core components initialize before configuration (logs) or without a Lookup path (logs again) — the initial notification is how they receive their configuration after booting on defaults.
func (*Configuration) JobRequests ¶
func (c *Configuration) JobRequests() ([]cf.JobRequest, error)
JobRequests implements cf.JobSource. It inspects every registered source's declared job flag (the flag must have been parsed by ParseFlags) and reports the requested jobs: the flag names the instance (the source's Owner), the value names the task to run on it (e.g. --postgresql.job=migrate → run task "migrate" on the "postgresql" instance). A task outside the source's declared Tasks set is an error. CLI-only: file and environment values never produce a job request. Empty (no job flag provided) returns an empty slice.
JobRequests must run after argv absorption; the framework calls it before any component initializes.
func (*Configuration) Name ¶
func (c *Configuration) Name() string
Name implements cf.CaerusComponent.
func (*Configuration) ParseFlags ¶
func (c *Configuration) ParseFlags(args []string) (rest []string, err error)
ParseFlags registers --<flag> for every currently registered source's flag-tagged fields and a --<source-name> file-path flag for every source with a Path, parses args, and re-applies the resulting values across all sources (flags win over env; env wins over file). The file-path flags override where each source's config file is read from; defaults are the sources' current paths, so an absent flag is a no-op.
Flags are a process-start overlay: the parsed field map is kept and re-applied on every subsequent Reload / ReloadAll; a path override persists on the source itself (reloads and the file watcher follow it).
Register all AddSource calls first so the flag definitions exist. Unknown flags and positional args are returned untouched — subcommands (`serve`, `migrate`) and app flags fall through to the caller.
func (*Configuration) Reload ¶
func (c *Configuration) Reload(name string) error
Reload forces a re-load of the named source, reapplying env overlay and AfterLoad even when the file bytes are unchanged. Use this after an external process env change (for example from a SIGHUP handler). The process environment is not watchable; without Reload (or a file change), new env values are invisible. Returns an error if the source is unknown or the load is rejected (previous value kept). Notifies the owner on success when the effective value changed.
func (*Configuration) ReloadAll ¶
func (c *Configuration) ReloadAll() error
ReloadAll forces Reload on every registered source. Owners are notified after all loads complete. The first load error is returned; later sources still run.
func (*Configuration) Shutdown ¶
func (c *Configuration) Shutdown(ctx context.Context) error
Shutdown implements cf.CaerusComponent. It stops the watcher and waits for the reload loop to exit. Safe to call even if Init never ran.
func (*Configuration) Sources ¶
func (c *Configuration) Sources() []string
Sources returns the names of registered configuration sources in sorted order. Returns nil when no sources are registered.
type Option ¶
type Option func(*options)
Option configures the configuration component at construction time.
func WithLogger ¶
WithLogger overrides the logger used for reload/watcher diagnostics. By default the component logs through the framework logs component (declared in GetDependencies); WithLogger is an explicit override for tests and embedded use and wins over the framework logger. slog.Default() remains the fallback only when neither is available.
type Source ¶
type Source[T any] struct { // Name is the logical name of this source (e.g. "mongodb"). It is the key // used by Get/MustGet and must be unique within the framework. Name string // Path is the configuration file path. It may be a symlink (as with // Kubernetes ConfigMap/Secret mounts), so the directory is watched and the // target is re-stat'ed on every event; see docs/K8S.md. Empty is allowed // when EnvPrefix is set (fileless / env-only source). // // A source with a Path also gets a --<Name> file-path flag in ParseFlags: // providing it overrides where the file is read from (defaults to this // Path), so the file location is itself a per-source CLI option. There is // no "config directory" bootstrap setting — each source declares its own // file, env and arg options. Path string // Format selects the file encoding. Ignored when Path is empty. Format Format // Owner is the Name of the component that consumes this configuration. On a // validated reload, the owner's OnConfigReload (if it implements // cf.ConfigReloader) is invoked. Empty disables reload dispatch. Owner string // EnvPrefix, when non-empty, overlays matching environment variables onto // the decoded value after the file is read (or onto a zero value when Path // is empty). Keys are EnvPrefix + `env` tag, or UPPER_SNAKE of the json // name. Example: EnvPrefix "POSTGRES_" and field `Host` → POSTGRES_HOST. EnvPrefix string // Job, when declared, registers a CLI-only job flag for this source's Owner. // The flag names the instance and the value names the task to run on it // (e.g. --postgresql.job=migrate); the framework reads the request via // cf.JobSource after argv absorption and routes it before serving. CLI-only: // the value lives in the parsed flag, never in the config file or // environment. Tasks (if non-empty) restricts the accepted task values; // a value outside the set fails JobRequests. The source must set Owner. Job cf.JobSpec // AfterLoad runs after file+env overlay and before Validate. Use it for // DSN/URL overlays (e.g. POSTGRES_DSN → OverlayDSN). Nil skips the step. AfterLoad func(*T) error // Validate runs after every successful load (initial and reload). It must // return nil for the new value to be accepted. On reload, a rejected value // keeps the previous one in effect. Validate func(*T) error }
Source describes one configuration source and how to interpret it. It is generic over the concrete config type, so each component gets its own strongly-typed config with no shared global struct.
Load order (later wins): file (if Path set) → env overlay (if EnvPrefix set) → flag overlay (if ParseFlags ran and the struct has flag tags) → AfterLoad → Validate. Files are the Kubernetes rotation plane (External Secrets → mount → fsnotify); env is for local/CI/PaaS; flags are a process-start overlay and do not hot-reload by themselves.