Documentation
¶
Overview ¶
Package backpressure provides unified client-side adaptive throttling for Go services.
A controller sits before a downstream operation, decides whether the operation should be attempted, and learns from caller-classified outcomes. The package is protocol agnostic: Redis, HTTP, RPC, database calls, queues, and custom operations all report the same generic Success, Failure, Neutral, and Overload signals.
Index ¶
- func AttrValue(attrs []Attr, key string) (string, bool)
- func Do[T any](ctx context.Context, controller *Controller, ...) (value T, err error)
- type Attr
- type Config
- type ConfigError
- type ConfigProvider
- type Controller
- func (c *Controller) Acquire(ctx context.Context, attrs ...Attr) (Permit, Decision)
- func (c *Controller) Allow(ctx context.Context, attrs ...Attr) Decision
- func (c *Controller) Name() string
- func (c *Controller) Report(outcome Outcome)
- func (c *Controller) Snapshot() Snapshot
- func (c *Controller) UpdateConfig(cfg Config)
- type Decision
- type ErrRejected
- type KeySampler
- type MultiObserver
- type NeutralPolicy
- type Observer
- type ObserverFunc
- type Option
- type Outcome
- type OutcomeClass
- type Permit
- type RandomSampler
- type Reason
- type Sampler
- type SequenceSampler
- type Snapshot
- type StaticConfig
- type Strategy
- type StrategyType
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Do ¶
func Do[T any]( ctx context.Context, controller *Controller, call func(context.Context) (T, error), fallback func(context.Context, Decision) (T, error), classify func(T, error) Outcome, attrs ...Attr, ) (value T, err error)
Do wraps an operation with Acquire, fallback, classification, and exactly-once reporting. If call panics, Do reports a failure and re-panics.
Example ¶
package main
import (
"context"
"fmt"
"github.com/istoliarov/go-backpressure"
)
func main() {
bp := backpressure.New("rpc", backpressure.DefaultConfig())
value, err := backpressure.Do(
context.Background(),
bp,
func(ctx context.Context) (string, error) {
return "value", nil
},
func(ctx context.Context, decision backpressure.Decision) (string, error) {
return "fallback", nil
},
func(value string, err error) backpressure.Outcome {
if err != nil {
return backpressure.Failure(err)
}
return backpressure.Success()
},
backpressure.AttrKey("operation", "lookup"),
)
fmt.Println(value, err)
}
Output: value <nil>
Types ¶
type Attr ¶
Attr carries optional low-cardinality context for sampling, snapshots, and observer callbacks.
type Config ¶
type Config struct {
Enabled bool
ShadowMode bool
Strategy StrategyType
MinPassPercent float64
MaxPassPercent float64
Window time.Duration
BucketCount int
MinSamples int64
SREK float64
PressureLimit float64
ErrorIncrease float64
OverloadIncrease float64
SuccessDecrease float64
DecayPerSecond float64
NeutralPolicy NeutralPolicy
}
Config controls a controller. Start from DefaultConfig for normal use.
The zero value is fail-open disabled after normalization. This avoids accidentally enabling traffic shedding from a partially initialized config. Explicit zero values are preserved for fields where zero is meaningful, such as MinSamples, MinPassPercent, MaxPassPercent, and pressure weights.
func DefaultConfig ¶
func DefaultConfig() Config
DefaultConfig returns conservative production defaults.
type ConfigError ¶
type ConfigError struct {
Issues []string
}
ConfigError describes non-fatal configuration normalization issues.
func (ConfigError) Error ¶
func (e ConfigError) Error() string
type ConfigProvider ¶
type ConfigProvider interface {
Snapshot() Config
}
ConfigProvider supplies runtime configuration snapshots.
type Controller ¶
type Controller struct {
// contains filtered or unexported fields
}
Controller decides whether client-side operations should be attempted and adapts from caller-reported outcomes.
func New ¶
func New(name string, cfg Config, opts ...Option) *Controller
New creates a controller. Pass DefaultConfig() unless you intentionally use a custom configuration.
func (*Controller) Acquire ¶
Acquire records an attempted operation, decides whether it should run, and returns a Permit for reporting the operation outcome when it is allowed.
Example ¶
package main
import (
"context"
"errors"
"fmt"
"time"
"github.com/istoliarov/go-backpressure"
)
func main() {
bp := backpressure.New("cache_read", backpressure.DefaultConfig())
permit, decision := bp.Acquire(context.Background(), backpressure.AttrKey("operation", "cache_read"))
if !decision.Allowed {
fmt.Println("fallback")
return
}
value, err := readCache(context.Background(), "item:42")
permit.Report(classifyCacheRead(value, err))
fmt.Println("done")
}
func readCache(_ context.Context, key string) (string, error) {
if key == "" {
return "", errors.New("empty key")
}
return "cached", nil
}
func classifyCacheRead(value string, err error) backpressure.Outcome {
switch {
case value != "":
return backpressure.Success()
case err == nil:
return backpressure.Neutral()
case errors.Is(err, context.DeadlineExceeded):
return backpressure.Failure(err).WithLatency(50 * time.Millisecond)
default:
return backpressure.Failure(err)
}
}
Output: done
func (*Controller) Allow ¶
func (c *Controller) Allow(ctx context.Context, attrs ...Attr) Decision
Allow records an attempted operation and returns only a decision. Prefer Acquire when the caller can report a result through the returned Permit.
func (*Controller) Name ¶
func (c *Controller) Name() string
Name returns the controller name used in snapshots and observer callbacks.
func (*Controller) Report ¶
func (c *Controller) Report(outcome Outcome)
Report reports an outcome without a Permit and counts it as an attempted operation for built-in strategies. Prefer Permit.Report when the result belongs to a specific Acquire call.
func (*Controller) Snapshot ¶
func (c *Controller) Snapshot() Snapshot
Snapshot returns the current controller state for debug endpoints and observability adapters.
func (*Controller) UpdateConfig ¶
func (c *Controller) UpdateConfig(cfg Config)
UpdateConfig updates the controller config when it uses the default StaticConfig provider. Controllers created with WithConfigProvider should be updated through that provider instead.
type Decision ¶
type Decision struct {
Allowed bool
Reason Reason
PassPercent float64
DropRatio float64
RetryAfter time.Duration
WouldReject bool
}
Decision describes the result of an Acquire or Allow call.
type ErrRejected ¶
type ErrRejected struct {
Decision Decision
}
ErrRejected is returned by Do and optional adapters when a request is locally rejected and no fallback is provided.
func (ErrRejected) Error ¶
func (e ErrRejected) Error() string
type KeySampler ¶
type KeySampler struct {
Key string
// contains filtered or unexported fields
}
KeySampler makes stable decisions for the same attribute value.
func NewKeySampler ¶
func NewKeySampler(key string) *KeySampler
NewKeySampler creates a sampler keyed by the given attribute name.
type MultiObserver ¶
type MultiObserver []Observer
MultiObserver fans callbacks out to several observers.
func (MultiObserver) OnConfigError ¶
func (m MultiObserver) OnConfigError(name string, err error)
func (MultiObserver) OnDecision ¶
func (m MultiObserver) OnDecision(name string, decision Decision, attrs []Attr)
type NeutralPolicy ¶
type NeutralPolicy string
const ( NeutralDoesNotAffect NeutralPolicy = "does_not_affect" NeutralCountsSuccess NeutralPolicy = "counts_success" NeutralCountsFailure NeutralPolicy = "counts_failure" )
type Observer ¶
type Observer interface {
OnDecision(name string, decision Decision, attrs []Attr)
OnReport(name string, outcome Outcome, snapshot Snapshot, attrs []Attr)
OnConfigError(name string, err error)
}
Observer receives synchronous best-effort callbacks for decisions, reports, and config normalization errors. Observer panics are recovered by Controller, but slow callbacks still add latency to the caller's hot path.
type ObserverFunc ¶
type ObserverFunc struct {
Decision func(name string, decision Decision, attrs []Attr)
Report func(name string, outcome Outcome, snapshot Snapshot, attrs []Attr)
ConfigError func(name string, err error)
}
ObserverFunc adapts individual functions into an Observer.
func (ObserverFunc) OnConfigError ¶
func (o ObserverFunc) OnConfigError(name string, err error)
func (ObserverFunc) OnDecision ¶
func (o ObserverFunc) OnDecision(name string, decision Decision, attrs []Attr)
type Option ¶
type Option func(*Controller)
Option customizes a Controller.
func WithConfigProvider ¶
func WithConfigProvider(provider ConfigProvider) Option
WithConfigProvider makes the controller read runtime config from provider.
func WithObserver ¶
WithObserver installs synchronous observer callbacks. Observer panics are recovered, but callbacks still run on the caller's hot path and should be fast and non-blocking.
func WithSampler ¶
WithSampler installs the sampler used by all built-in strategies.
func WithStrategy ¶
func WithStrategy(strategyType StrategyType, strategy Strategy) Option
WithStrategy registers a custom strategy type. The controller will use it when Config.Strategy matches strategyType.
type Outcome ¶
type Outcome struct {
Class OutcomeClass
Err error
Latency time.Duration
Weight float64
}
Outcome is the caller-classified result of an attempted operation.
func Neutral ¶
func Neutral() Outcome
Neutral reports a valid result that should not worsen backpressure state.
func Overload ¶
Overload reports an explicit overload signal such as 429, 503, or resource exhausted.
func Success ¶
func Success() Outcome
Success reports that the downstream handled the operation well.
func (Outcome) WithLatency ¶
WithLatency attaches downstream latency to an outcome.
func (Outcome) WithWeight ¶
WithWeight adjusts the outcome impact for strategies that use weights.
type OutcomeClass ¶
type OutcomeClass int
OutcomeClass classifies an operation result for backpressure purposes.
const ( OutcomeSuccess OutcomeClass = iota OutcomeFailure OutcomeNeutral OutcomeOverload )
func (OutcomeClass) String ¶
func (c OutcomeClass) String() string
type Permit ¶
type Permit interface {
Report(outcome Outcome)
}
Permit reports the result of an allowed operation. Implementations are safe to call more than once; only the first report is applied.
type RandomSampler ¶
type RandomSampler struct {
// contains filtered or unexported fields
}
RandomSampler makes pseudo-random decisions without using the global math/rand source.
func NewRandomSampler ¶
func NewRandomSampler(seed uint64) *RandomSampler
NewRandomSampler creates a sampler with the provided seed. A zero seed uses the current time.
type SequenceSampler ¶
type SequenceSampler struct {
// contains filtered or unexported fields
}
SequenceSampler distributes decisions evenly across the request stream.
func NewSequenceSampler ¶
func NewSequenceSampler() *SequenceSampler
NewSequenceSampler creates a stream-oriented sampler.
type Snapshot ¶
type Snapshot struct {
Name string
Enabled bool
Strategy StrategyType
PassPercent float64
DropRatio float64
Pressure float64
WindowRequests int64
WindowAccepts int64
WindowFailures int64
LocalRejects int64
// ShadowRejects counts requests that would have been rejected while
// ShadowMode allowed them through.
ShadowRejects int64
Config Config
UpdatedAt time.Time
}
Snapshot is a point-in-time view of controller state.
type StaticConfig ¶
type StaticConfig struct {
// contains filtered or unexported fields
}
func NewStaticConfig ¶
func NewStaticConfig(cfg Config) *StaticConfig
NewStaticConfig creates a concurrency-safe in-memory ConfigProvider.
func (*StaticConfig) Snapshot ¶
func (c *StaticConfig) Snapshot() Config
Snapshot returns the latest stored configuration.
func (*StaticConfig) Store ¶
func (c *StaticConfig) Store(cfg Config)
Store replaces the current configuration.
type Strategy ¶
type Strategy interface {
Allow(now time.Time, cfg Config, attrs []Attr) Decision
Report(now time.Time, cfg Config, outcome Outcome, attrs []Attr)
Snapshot(now time.Time, cfg Config) Snapshot
}
Strategy is the algorithm contract implemented by built-in strategies.
Custom strategies are supported for advanced consumers, but this interface is experimental until v1 and may change based on real integrations.
type StrategyType ¶
type StrategyType string
const ( StrategySREAdaptive StrategyType = "sre_adaptive" StrategyPressure StrategyType = "pressure" )
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
examples
|
|
|
cache
command
|
|
|
database
command
|
|
|
generic_operation
command
|
|
|
grpc_style
command
|
|
|
queue
command
|
|
|
Package httpbp provides an optional net/http RoundTripper adapter for backpressure controllers.
|
Package httpbp provides an optional net/http RoundTripper adapter for backpressure controllers. |