engine

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: May 30, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package engine holds the rules and decision logic that adapters consult on every wrapped operation. It depends only on the standard library and the chaotic fault package.

Index

Constants

View Source
const (
	ReasonCounter       = "counter"
	ReasonRateLimit     = "rate_limit"
	ReasonMaxConcurrent = "max_concurrent"
	ReasonFailureBudget = "failure_budget"
	ReasonDisabled      = "disabled"
	ReasonKillSwitch    = "killswitch"
)

Skip reasons passed to Observer.RuleSkipped. Observers may switch on these instead of matching free-form strings.

Variables

This section is empty.

Functions

This section is empty.

Types

type Action

type Action interface {
	Before(ctx context.Context) error
	After(ctx context.Context) error
}

Action is what Eval returns; adapters execute it around the wrapped call. Before runs prior to the call. After runs after call.

var Pass Action = &passAction{}

Pass is the canonical no-op action.

type Engine

type Engine struct {
	// contains filtered or unexported fields
}

Engine holds the rules and decision logic. Engines are not safe to copy - always pass as *Engine. AddRule is safe for concurrent use, Eval is too.

func New

func New(opts ...Option) *Engine

New constructs an engine with no rules. Options may inject an Observer, a KillSwitch, or other.

func (*Engine) AddRule

func (e *Engine) AddRule(r Rule) *Engine

AddRule appends a rule. Returns the engine for chaining. Append is implemented as a copy-on-write swap of the rule slice so concurrent Evals never see a torn slice.

func (*Engine) AllHits

func (e *Engine) AllHits() map[string]int

AllHits returns a snapshot of hit counts for every named rule registered with the engine, including rules that have not yet fired (value 0).

func (*Engine) Enabled

func (e *Engine) Enabled() bool

Enabled reports whether the engine has any rules. Adapters call this before constructing an Op so the no-op path stays alloc-free. Nil-safe: a nil engine reports false.

func (*Engine) Eval

func (e *Engine) Eval(ctx context.Context, op Op) Action

Eval evaluates the op against all configured rules and returns the matching Action, or Pass if no rule matches or the engine is disabled.

func (*Engine) Hits

func (e *Engine) Hits(name string) int

Hits returns the number of times a named rule has fired. Unknown names return 0. Safe for concurrent use.

func (*Engine) ReplaceRules

func (e *Engine) ReplaceRules(rs RuleSet)

ReplaceRules atomically swaps the active rule set. Used by rule sources on reload. Concurrent Evals see either the old or the new set, never a torn one. Hit counters are rebuilt for the new set's named rules.

func (*Engine) Reset

func (e *Engine) Reset()

Reset clears all rules and hit counters. Idempotent and cheap.

type KillSwitch

type KillSwitch func(ctx context.Context, op Op) bool

KillSwitch lets a caller short-circuit chaos. If it returns true for the current Op, Eval returns Pass without consulting any rule. The default engine has no kill switch (every call is evaluated).

type Kind

type Kind int

Kind identifies which adapter produced an Op. Do not renumber existing values.

const (
	OpHTTPClient Kind = iota + 1
	OpHTTPServer
	OpSQL
	OpGRPCClient
	OpGRPCServer
)

Op kind constants identify which adapter produced an Op.

type Observer

type Observer interface {
	RuleFired(ruleName string, op Op, action Action)
	RuleSkipped(ruleName string, op Op, reason string)
}

Observer receives events from the engine each time it evaluates a named rule. v1 ships no concrete implementations. Users supply their own via WithObserver. The always-on per-named-rule hit counter (Engine.Hits) does not require an observer.

Observer methods are called synchronously on the request path. Keep them cheap, do not block.

type Op

type Op struct {
	Kind   Kind
	Name   string
	Method string
	Attrs  map[string]string
}

Op describes a single intercepted call. Adapters construct an Op only after Engine.Enabled() returns true, so the no-op path allocates nothing.

type Option

type Option func(*Engine)

Option configures an Engine at construction time.

func WithFailureBudget

func WithFailureBudget(maxErrorRate float64, window int) Option

WithFailureBudget stops injecting faults once the observed error rate over a sliding window of the last window calls reaches maxErrorRate. Requires the adapters to report outcomes (they do, via OutcomeReporter). Panics if maxErrorRate is outside [0, 1] or window < 1.

func WithKillSwitch

func WithKillSwitch(ks KillSwitch) Option

WithKillSwitch attaches a kill switch. Pass nil to clear.

func WithObserver

func WithObserver(obs Observer) Option

WithObserver attaches an Observer to the engine. Pass nil to clear.

func WithRuleSource

func WithRuleSource(rs RuleSet) Option

WithRuleSource backs the engine with rs at construction (instead of AddRule).

type OutcomeReporter

type OutcomeReporter interface {
	Outcome(ctx context.Context, callErr error)
}

OutcomeReporter is an optional interface an Action may implement to receive the result of the wrapped call. Adapters call Outcome (when implemented) after the wrapped boundary returns. callErr is the wrapped call's error (nil or success). It is not invoked Before short-circuits the call.

type Rule

type Rule struct {
	// contains filtered or unexported fields
}

Rule is a single match-counter-faults triple. Construct with NewRule and pass to Engine.AddRule. Rule values may be copied (e.g., by Named), but they share state via internal pointers - never modify a Rule's selectors or faults after passing it to AddRule.

func NewRule

func NewRule(opts ...RuleOption) Rule

NewRule constructs a Rule. The default counter is Always, default action is no faults (Pass).

func (Rule) Name

func (r Rule) Name() string

Name reports the rule's name, or "" if it has none.

func (Rule) Named

func (r Rule) Named(name string) Rule

Named tags the rule for assertions and observability. Returns a copy of the rule (with shared mutable state - selectors/counter/faults) so the pre-named rule remains usable.

type RuleOption

type RuleOption func(*Rule)

RuleOption configures a Rule during construction.

func Always

func Always() RuleOption

Always is default counter: every match fires the rule.

func MatchAttr

func MatchAttr(key, value string) RuleOption

MatchAttr matches Ops whose Attrs[key] equals value.

func MatchKind

func MatchKind(kinds ...Kind) RuleOption

MatchKind matches Ops whose Kind appears in kinds. With zero arguments, matches nothing.

func MatchName

func MatchName(pattern string) RuleOption

MatchName matches Ops whose Name satisfies path.Match(pattern, Name). Patterns support *, ?, and [...]. * does not cross /.

func MatchPredicate

func MatchPredicate(fn func(context.Context, Op) bool) RuleOption

MatchPredicate matches Ops for which fn returns true.

func Probability

func Probability(p float64, seed int64) RuleOption

Probability makes the rule fire on each match independently with probability p. Seed makes the decision deterministic across runs. Panics if p is outside [0,1].

func Range

func Range(from, to int) RuleOption

Range makes the rule fire on matches[from:to] (1-indexed, inclusive). If from > to or either is < 1, the rule never fires.

func Times

func Times(n int) RuleOption

Times makes the rule fire on the first n matches. After n, the rule never fires again until Engine.Reset clears the counter.

func WithFault

func WithFault(f fault.Fault) RuleOption

WithFault attaches a single fault. Equivalent to WithFaults(f).

func WithFaults

func WithFaults(fs ...fault.Fault) RuleOption

WithFaults attaches faults that execute in order inside Action.Before. The first fault returning a non-nil error short-circuits the chain.

type RuleSet

type RuleSet interface {
	Len() int
	Snapshot() []Rule
}

RuleSet is the engine's view of its current rules. The engine never holds a snapshot across Eval calls - it loads a fresh one each time.

func NewRuleSet

func NewRuleSet(rules []Rule) RuleSet

NewRuleSet returns an in-memory RuleSet backed by the given rules. Sources (file/http) build their rules then call ReplaceRules(NewRuleSet(rules)).

Jump to

Keyboard shortcuts

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