contracts

package
v0.15.0 Latest Latest
Warning

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

Go to latest
Published: May 16, 2026 License: MIT Imports: 2 Imported by: 0

Documentation

Overview

Package contracts is the **public, stable** surface of FastConf interfaces.

Third-party packages implement these interfaces to extend FastConf with custom configuration sources (Vault, Consul, Etcd, AWS AppConfig, ...) and custom encodings (TOML, HCL, JSON5, ...). The interfaces are intentionally minimal so that v0.x → v1 migration is cheap.

The pipeline packages (fastconf/pkg/provider, fastconf/pkg/decoder, ...) type-alias these interfaces so the same value satisfies both the internal and the public contract — no adapter shim required.

Stability

Anything in this package follows semver. Breaking changes require a major version bump. Anything outside this package (and the top-level fastconf package) is implementation detail.

Files

  • provider.go — Provider + Resumable + ErrResumeUnsupported
  • snapshot.go — Snapshot + SnapshotProvider
  • event.go — Event
  • codec.go — Codec
  • source.go — Source
  • priority.go — PriorityStatic .. PriorityCLI constants

Index

Constants

View Source
const (
	PriorityDotEnv  = 5 // .env file defaults — lowest band; overridden by all built-in providers
	PriorityStatic  = 10
	PriorityOverlay = 20
	PriorityKV      = 30
	PriorityK8s     = 40
	PriorityEnv     = 50
	PriorityCLI     = 60
)

Standard priority bands. Higher values override lower ones during merge.

File discovery uses 1000-2999 internally; provider bands are kept small (10-99) and the framework offsets them above file layers when reporting Snapshot().Sources, so providers always win over file layers.

Static / file-like    10  (PriorityStatic)
Overlay providers     20  (PriorityOverlay)
Remote KV             30  (PriorityKV)
Kubernetes            40  (PriorityK8s)
Environment           50  (PriorityEnv)
Command-line flags    60  (PriorityCLI)  ← highest

Custom providers SHOULD pick a value within an appropriate band so that merge order remains predictable across heterogeneous deployments.

Variables

View Source
var ErrResumeUnsupported = errResumeUnsupported{}

ErrResumeUnsupported is returned by Resumable.WatchFrom when the requested resume point is no longer recoverable (compaction, retention loss). The framework converts this into a metric + audit annotation and falls back to a cold Watch.

Functions

This section is empty.

Types

type Attr

type Attr struct {
	Key   string
	Value any
}

Attr is a (key, value) pair used by tracer attribute fan-out. (Introduced by BUG-706; see internal/obs.EnrichAttrs.)

type Codec

type Codec interface {
	// Decode parses data into a top-level map. Documents whose root is not
	// an object (e.g. a top-level YAML sequence) MUST return an error
	// rather than wrapping the value in a synthetic key.
	Decode(data []byte) (map[string]any, error)
}

Codec decodes a byte stream of a specific encoding (yaml, json, toml, ...) into a generic map[string]any used by the merge stage. Implementations MUST be safe for concurrent use; the framework calls Decode from the reload goroutine but may invoke a single Codec instance from validation or test helpers in parallel.

type Event

type Event struct {
	// Source identifies which provider/source emitted the event. Usually
	// equals Provider.Name(), but providers that fan out multiple sub-keys
	// MAY use a more specific identifier (e.g. "vault://secret/db").
	Source string
	// Reason is a free-form human readable cause: "watch", "poll-diff",
	// "etag-changed", etc. Used for log lines and metrics labels.
	Reason string
	// Revision, when non-empty, mirrors Snapshot.Revision and lets
	// downstream consumers (e.g. AuditSink) skip duplicate fan-outs.
	Revision string
	// At is the time the change was observed by the provider.
	At time.Time
}

Event is emitted by a Provider when its underlying source changes.

type Generator

type Generator interface {
	// Name is used for diagnostics and Source.Name when the generator
	// does not stamp its own.
	Name() string
	// Generate returns the synthetic Sources contributed for this reload.
	// Returning a nil slice and a nil error is a valid "nothing to add"
	// outcome.
	Generate(ctx context.Context) ([]Source, error)
}

Generator dynamically synthesises one or more Source layers during the assemble stage of a reload. Unlike a Provider, which returns a single map[string]any, a Generator can produce multiple Sources with distinct codecs and priorities — useful for injecting build-info / shell-out / K8s downward-api / sealed-secret style data.

Generators run on the single reload goroutine, so implementations must respect ctx cancellation and bound their own runtime (e.g. timeouts for shell-out generators). Returning an error aborts the reload (failure-safe — previous *State[T] is preserved).

type Provider

type Provider interface {
	// Name is used for diagnostics, deduplication and Snapshot().Sources.
	// It SHOULD be stable across runs and unique within a Manager.
	Name() string

	// Priority controls merge order: higher values override lower ones.
	// Use the Priority* constants in this package for well-known bands.
	Priority() int

	// Load returns a one-shot snapshot of this provider's contribution.
	// The returned map MUST NOT be retained or mutated by the caller; the
	// provider remains the owner.
	Load(ctx context.Context) (map[string]any, error)

	// Watch optionally streams change events. Returning (nil, nil) means
	// "no native change notifications". The returned channel SHOULD be
	// closed when ctx is cancelled.
	Watch(ctx context.Context) (<-chan Event, error)
}

Provider is the contract every dynamic configuration source implements.

A Provider participates in the reload pipeline as a single layer: its Load method returns a snapshot map that is merged on top of file-discovery layers (and other providers) ordered by Priority — higher Priority wins.

Watch is optional: providers that have no native change-notification channel should return (nil, nil), and the framework will treat them as polled / static. Returning a non-nil channel makes the provider eligible for event-driven reloads in conjunction with Manager's watcher.

type Resumable

type Resumable interface {
	WatchFrom(ctx context.Context, lastRev string) (<-chan Event, error)
}

Resumable is the Phase 25 optional extension. Providers that can re-subscribe from a known revision (etcd-style "Watch from last_revision", NATS JetStream "DeliverByStartSequence", Vault kv-v2 metadata version) implement WatchFrom. The framework remembers the last Event.Revision (or Snapshot.Revision) it observed for each provider and passes it back on the next (re)subscribe. Providers that do not implement Resumable continue to call Watch as before, preserving backwards compatibility.

WatchFrom MUST behave like Watch when lastRev is empty (cold subscribe). When lastRev is non-empty, the provider SHOULD attempt to deliver every change observed strictly AFTER that revision; if the upstream cannot honour the request (e.g. revision compacted), the provider MUST return ErrResumeUnsupported so the framework falls back to Watch and the caller can mark the gap in audit.

type Snapshot

type Snapshot struct {
	Map      map[string]any
	Revision string
	Stale    bool
}

Snapshot is the richer return type used by SnapshotProvider. It augments the legacy Load() map with two additional pieces of metadata that align FastConf's reload pipeline with etcd / Vault / Consul-style versioning:

  • Revision is an opaque, monotonically-meaningful version string (e.g. etcd revision, Vault KV current_version, Consul ModifyIndex). The framework records it per-provider and skips the rest of the pipeline when every provider's Revision is unchanged AND no file layer mutated.
  • Stale means "this snapshot is best-effort and the provider could not verify it is fresh" (degraded read from a cache after the upstream went down). The framework logs a warning and forwards Stale through ReloadCause so audit pipelines can surface the degradation.

Map has identical semantics to Provider.Load — it MUST NOT be retained or mutated by the caller; the provider remains the owner.

type SnapshotProvider

type SnapshotProvider interface {
	Provider
	LoadSnapshot(ctx context.Context) (Snapshot, error)
}

SnapshotProvider is an optional extension to Provider. Providers that can expose a revision SHOULD implement it; Manager will prefer LoadSnapshot over Load when both are available. Providers that only implement Load are transparently adapted by the framework via Snapshot{Map: m}.

type Source

type Source struct {
	Name  string
	Codec string
	Data  []byte
}

Source is a self-describing in-memory contributor: the union of (name, codec, bytes). It is the lowest-friction way to inject inline configuration in tests, examples and bootstrap code without writing a full Provider. Typical usage:

contracts.Source{Name: "inline", Codec: "yaml", Data: []byte("a: 1")}

type Span

type Span interface {
	End()
	RecordError(err error)
	SetAttribute(key string, value any)
}

Span is the minimal tracing-span contract used by FastConf's observability layer. Sub-modules (otel/) and the root package both reference this type to avoid circular imports between internal/obs and the root package.

Jump to

Keyboard shortcuts

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