Documentation
¶
Overview ¶
Package hotreload implements live config reloading for BubbleFish Nexus source files. It watches the sources directory with fsnotify and applies config changes atomically via an RWMutex.
Hot reload scope (per Tech Spec Section 14.1):
- Source config changes: applied atomically. In-flight handlers complete with the old config. Auth hot path uses RLock; reload uses Lock.
- Destination config changes: WARN logged, old config kept. Restart required.
- Compiled JSON: written atomically (temp file + fsync + os.Rename).
INVARIANTS:
- NEVER apply destination config changes via hot reload.
- NEVER write compiled JSON non-atomically.
- watchLoop goroutine exits cleanly when stop channel is closed.
- NEVER use Lock() on the auth hot path. Only RLock().
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Config ¶
type Config struct {
// SourcesDir is the directory watched for *.toml source config files.
SourcesDir string
// ConfigDir is the root config directory (used for compiled JSON output).
ConfigDir string
// Mu is the shared RWMutex that guards the daemon's config pointer.
// Auth hot path must use RLock; reload uses Lock.
Mu *sync.RWMutex
// Snapshot returns the current *config.Config. The Watcher calls this
// while holding Mu.RLock() — the caller must not acquire any additional locks.
Snapshot func() *config.Config
// Apply atomically installs a new *config.Config. The Watcher calls this
// while holding Mu.Lock() — the caller must not acquire any additional locks.
Apply func(*config.Config)
// Reload loads a fresh *config.Config from disk. Called by the Watcher
// outside of any mutex; must be safe to call from a goroutine.
Reload func() (*config.Config, error)
// SigningKey is the resolved signing key bytes. When non-nil, the watcher
// re-verifies compiled config signatures before applying a reload.
// Nil means signing is disabled — no verification is performed.
// NEVER log this value.
SigningKey []byte
// SigningEvent is called when a config signature verification failure
// occurs during hot reload. May be nil if signing is disabled.
SigningEvent signing.SecurityEventFunc
// Logger is the structured logger for watcher events.
Logger *slog.Logger
}
Config holds all parameters required to construct a Watcher.
type Watcher ¶
type Watcher struct {
// contains filtered or unexported fields
}
Watcher monitors the sources directory for *.toml changes and hot-reloads source configuration. All state is in struct fields — no package-level vars.
func New ¶
New creates a Watcher from cfg. Call Start() to begin watching. Panics if any required field in cfg is nil.
func (*Watcher) Start ¶
Start adds the sources directory to an fsnotify watcher and launches the watchLoop goroutine. Returns an error if the directory cannot be watched (e.g. it does not exist); the daemon should log a warning and continue.
Start must be called at most once. The goroutine is stopped by calling Stop().