engine

package
v0.1.13 Latest Latest
Warning

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

Go to latest
Published: Oct 11, 2026 License: MIT Imports: 8 Imported by: 0

Documentation

Overview

Package engine enforces bounded concurrency with backpressure, request deduplication (singleflight), and integration with adaptive limiting and the circuit breaker. It uses only the standard library and core/bus: admission is a bus lane (the Serve lane of the process's bus, or one of the engine's own), IO slots a bus semaphore, singleflight a mutex-guarded call table. No unbounded goroutines (invariant I13); panics in submitted functions are recovered and returned as errors so they never crash the process.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrOverloaded is returned when the in-flight queue is full (backpressure).
	ErrOverloaded = errors.New("engine: overloaded")
	// ErrInvalidConfig is returned by New for non-positive pool sizes.
	ErrInvalidConfig = errors.New("engine: invalid config")
	// ErrClosed is returned by Submit after Close.
	ErrClosed = errors.New("engine: closed")
)

Sentinel errors.

Functions

func Run added in v0.1.13

func Run[T any](ctx context.Context, e *Engine, fn func(context.Context) (T, error)) (T, error)

Run runs fn on e under the rate limit, its panics recovered, but outside the lane, the breaker, the adaptive limit and the IO slots: for a call ending a transaction, which must reach its database however it is held back, and holds its connection already.

func Submit added in v0.1.13

func Submit[T any](ctx context.Context, e *Engine, key string, fn func(context.Context) (T, error)) (T, error)

Submit schedules fn on e under backpressure and returns fn's result value and error. It returns ErrOverloaded if the in-flight queue is full, ErrCircuitOpen if the breaker is open, ErrRateLimited if concurrency exceeds the adaptive limit. Concurrent calls with the same non-empty key share a single execution (singleflight) and all receive the leader's result. An empty key opts out of de-duplication (writes/unique ops). Panics in fn are recovered as errors.

Types

type Engine

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

Engine bounds concurrency and deduplicates concurrent identical requests.

func New

func New(opts ...Option) (*Engine, error)

New returns an Engine with the given options and sane defaults.

func (*Engine) Close

func (e *Engine) Close()

Close rejects new work and waits for all in-flight submissions.

func (*Engine) Drain

func (e *Engine) Drain(ctx context.Context) error

Drain rejects new submissions and waits for admitted callers and detached singleflight execution goroutines to return.

type Option

type Option func(*config)

Option configures an Engine.

func WithBreaker

func WithBreaker(b *ratelimit.Breaker) Option

WithBreaker attaches a circuit breaker.

func WithFailureClassifier

func WithFailureClassifier(classify func(error) bool) Option

WithFailureClassifier decides whether a non-nil execution error represents provider/system health and should affect AIMD and the circuit breaker.

func WithIOPool

func WithIOPool(n int) Option

WithIOPool sets the IO concurrency (<= DB connection pool size).

func WithLane added in v0.1.13

func WithLane(l *bus.Lane) Option

WithLane admits submissions on lane, such as the Serve lane of the process's bus, instead of an in-flight bound of the engine's own; it replaces the max in-flight option.

func WithLimiter

func WithLimiter(l *ratelimit.Adaptive) Option

WithLimiter attaches an adaptive limiter for AIMD feedback.

func WithMaxInflight

func WithMaxInflight(n int) Option

WithMaxInflight sets the bounded in-flight queue (backpressure).

func WithQuota added in v0.1.12

func WithQuota(q *Quota) Option

WithQuota bounds IO by a quota shared with other engines; it replaces the IO pool, limiter, rate limiter and breaker options.

func WithRPSLimiter

func WithRPSLimiter(l *ratelimit.TokenBucket) Option

WithRPSLimiter attaches a token-bucket request-rate limiter.

type Quota added in v0.1.12

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

Quota is what bounds IO across engines: the IO slots, the adaptive limiter, the request-rate limiter and the circuit breaker. Engines of successive configurations of one process share it, so a reload never lets the old and the new configuration together exceed the IO pool, and Update applies new limits to the work already running.

func NewQuota added in v0.1.12

func NewQuota(io int) *Quota

NewQuota returns a quota of io slots and no limiter, rate limit or breaker.

func NewQuotaOn added in v0.1.13

func NewQuotaOn(io *bus.Semaphore) *Quota

NewQuotaOn returns a quota whose IO slots are io, such as the IO semaphore of the process's bus, and no limiter, rate limit or breaker.

func (*Quota) Update added in v0.1.12

func (q *Quota) Update(io int, limiter *ratelimit.Adaptive, rps *ratelimit.TokenBucket, breaker *ratelimit.Breaker)

Update sets the IO slots and replaces the limiter, rate limiter and breaker (nil turns one off). Work holding a slot keeps it; when the slots shrink, new work waits until the running work fits.

Jump to

Keyboard shortcuts

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