Documentation
¶
Overview ¶
Package breakers provides named, dynamically-controllable on/off switches for individual functional surfaces of the rendezvous process. Operators flip a switch by writing a JSON file (<store-dir>/breakers.json); a file watcher reloads the state every 2 s and call sites consult the breaker before serving the affected request type.
Three states per breaker:
closed — normal operation (default). Allow.
half_open — log a warning, but allow. Use for canary testing
or to observe call frequency without disrupting
traffic.
open — deny. The serving site returns an appropriate
error to the caller (typically a 503-equivalent
with the operator-supplied reason).
Names are flat strings, conventionally dotted paths reflecting the component and action being gated (e.g. "registry.register", "beacon.punch", "snapshot.write"). The Manager is permissive: it accepts any name on the read path; a missing breaker is treated as "closed" (allow). Unknown names in the JSON file are kept but silently unused — write-time tolerance lets operators stage a name before its call site is wired.
Index ¶
- func Watch(m *Manager, path string, interval time.Duration, stop <-chan struct{})
- type Breaker
- type Manager
- func (m *Manager) Allow(name string) (bool, State)
- func (m *Manager) Reason(name string) string
- func (m *Manager) Replace(breakers map[string]*Breaker)
- func (m *Manager) Set(name string, state State, reason string)
- func (m *Manager) SetClock(fn func() time.Time)
- func (m *Manager) Size() int
- func (m *Manager) Snapshot() []Breaker
- type State
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Watch ¶
Watch polls path for mtime+size changes every interval and atomically reloads breakers into the Manager when the file changes.
Operational contract — pinned by tests; identical in spirit to the rate-limit whitelist watcher:
- Never blocks startup, the registry, the beacon, or any request path. Runs in its own goroutine; the only state it mutates is the Manager, via Replace.
- Fail-open: missing file is fine (no breakers installed; every name returns Allow=closed via Manager's default-allow). Parse, stat, or apply errors are logged at WARN and leave whatever map is currently installed in place.
- Idempotent: same file content (unchanged mtime + size) is a no-op.
- File removal reverts the Manager to an empty map on the next tick (logged INFO).
File format — JSON object, name → {state, reason?}:
{
"registry.register": {"state": "closed"},
"beacon.punch": {"state": "open", "reason": "maintenance"},
"dashboard.public_stats": {"state": "half_open","reason": "soaking pre-lockdown"}
}
state must be one of "closed", "half_open", "open" (case-insensitive, with the same aliases ParseState accepts). reason is operator-facing free text surfaced in error messages when a breaker is open.
Types ¶
type Breaker ¶
type Breaker struct {
Name string `json:"name"`
State State `json:"-"` // serialised via custom marshalling
StateString string `json:"state"`
Reason string `json:"reason,omitempty"`
UpdatedAt time.Time `json:"updated_at,omitempty"`
}
Breaker is a snapshot of one named switch's state.
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager holds the live breaker map. Safe for concurrent use.
func New ¶
func New() *Manager
New returns an empty Manager. No breakers are pre-registered; Allow on any unknown name returns (true, Closed) — the default- allow semantic ensures a missing JSON file or a misspelled name can never cut off service.
func (*Manager) Allow ¶
Allow consults the named breaker and returns:
(true, Closed) — normal operation (true, HalfOpen) — caller should log a warning, then proceed (false, Open) — caller must NOT proceed; return an error
An unknown name is treated as Closed (default-allow) so a request path is never blocked by a typo. The state is returned alongside the bool so the caller can log appropriately without a second lookup.
func (*Manager) Reason ¶
Reason returns the operator-supplied reason for the named breaker's current state, or "" if no breaker is registered. Use in error messages surfaced to callers when Allow returns false.
func (*Manager) Replace ¶
Replace atomically swaps the full breaker map. Used by the file watcher to apply a fresh JSON snapshot in one shot.
func (*Manager) Set ¶
Set installs or replaces one breaker. Audit-logged via the Manager's updated-at timestamp; callers who want a separate event sink should wrap this method.
type State ¶
type State int
State enumerates the three configurable states a breaker can be in.
const ( // Closed means normal operation: Allow returns (true, Closed). Closed State = iota // HalfOpen means warn-but-allow: Allow returns (true, HalfOpen). // Call sites should log a warning so operators can observe. HalfOpen // Open means deny: Allow returns (false, Open). Call sites should // surface the breaker's reason in any error returned to the caller. Open )
func ParseState ¶
ParseState parses a wire-format state string. Accepts the canonical "closed" / "half_open" / "open" plus a few common aliases ("half-open", "halfopen") so the JSON file is forgiving. Unknown values return an error so a typo doesn't silently become Closed.