Documentation
¶
Overview ¶
Package resilience composes explicit synchronous resilience policies and owns process-local retry-plus-hedge amplification accounting.
The package deliberately does not implement retry, hedge, circuit-breaker, rate-limit, timeout, fallback, bulkhead, semaphore, or cache algorithms. Focused packages implement those decisions and adapt them through Policy, Stage, Execution, and WorkBudget.
Policies are ordered outer-to-inner. Logical policies must precede attempt policies so a logical policy can invoke the attempt stack repeatedly while each physical attempt remains independently observable and budgeted. Execution is synchronous and never moves an operation into a goroutine.
Index ¶
- Constants
- Variables
- func AdmitAttempt(ctx context.Context, origin AttemptOrigin, parent uint64, startedAt time.Time) (context.Context, Attempt, Permit, error)
- func WithBudgetScope(ctx context.Context, scope WorkBudgetScope) (context.Context, error)
- type Attempt
- type AttemptOrigin
- type Budget
- type BudgetConfig
- type BudgetRejectionError
- type BudgetScope
- type BudgetSnapshot
- type Clock
- type ConfigurationError
- type Event
- type EventKind
- type Execution
- type Executor
- func (executor Executor[T]) Execute(ctx context.Context, metadata Metadata, operation Operation[T]) (result Result[T])
- func (executor Executor[T]) Policies() []PolicyDescriptor
- func (executor Executor[T]) WithClock(clock Clock) (Executor[T], error)
- func (executor Executor[T]) WithObserver(observer Observer, maxEvents int) (Executor[T], error)
- func (executor Executor[T]) WithTimeline(maxEvents int) (Executor[T], error)
- type IgnoredError
- type LocalRejectionError
- type Metadata
- type Observer
- type ObserverFunc
- type Operation
- type Outcome
- type OutcomeKind
- type Permit
- type Policy
- type PolicyDescriptor
- type PolicyExecutionError
- type PolicyID
- type RejectionReason
- type Result
- func Failure[T any](value T, err error, attempt Attempt) Result[T]
- func Ignored[T any](attempt Attempt, reason string) Result[T]
- func LocalRejection[T any](attempt Attempt, policy PolicyID, reason string, cause error) Result[T]
- func PolicyFailure[T any](attempt Attempt, policy PolicyID, stage string, cause error) Result[T]
- func Success[T any](value T, attempt Attempt) Result[T]
- type Scope
- type Stage
- type WorkBudget
- type WorkBudgetScope
- type WorkPermit
Examples ¶
Constants ¶
const MaxIdentityLength = 128
MaxIdentityLength bounds identifiers retained by diagnostics and budgets.
Variables ¶
var ( // ErrBudgetRejected identifies local work-amplification denial. ErrBudgetRejected = errors.New("resilience: work budget rejected") // ErrBudgetClosed identifies use after a logical budget scope closed. ErrBudgetClosed = errors.New("resilience: budget scope closed") // ErrBudgetScopeMismatch identifies use of a scope for different metadata. ErrBudgetScopeMismatch = errors.New("resilience: budget scope mismatch") // ErrBudgetAlreadyAttached identifies nested scope creation on a budget context. ErrBudgetAlreadyAttached = errors.New("resilience: budget already attached") // ErrBudgetScopeRequired identifies work admission without a shared scope. ErrBudgetScopeRequired = errors.New("resilience: budget scope required") // ErrPermitCompleted identifies duplicate permit completion. ErrPermitCompleted = errors.New("resilience: permit already completed") // ErrPermitExpired identifies completion after abandoned-capacity recovery. ErrPermitExpired = errors.New("resilience: permit expired") )
var ( // ErrInvalidComposition identifies an executor policy configuration error. ErrInvalidComposition = errors.New("resilience: invalid composition") // ErrInvalidMetadata identifies missing or unbounded execution metadata. ErrInvalidMetadata = errors.New("resilience: invalid metadata") // ErrInvalidAttempt identifies inconsistent physical-attempt metadata. ErrInvalidAttempt = errors.New("resilience: invalid attempt") // ErrNilOperation identifies an execution without an operation. ErrNilOperation = errors.New("resilience: nil operation") // ErrLocalRejection identifies local policy denial without downstream work. ErrLocalRejection = errors.New("resilience: local rejection") // ErrIgnored identifies work deliberately omitted by an owning policy. ErrIgnored = errors.New("resilience: ignored") // ErrPolicyFailure identifies failure in policy logic rather than the operation. ErrPolicyFailure = errors.New("resilience: policy failure") )
Functions ¶
func AdmitAttempt ¶
func AdmitAttempt(ctx context.Context, origin AttemptOrigin, parent uint64, startedAt time.Time) (context.Context, Attempt, Permit, error)
AdmitAttempt allocates unique physical-attempt lineage, admits it through the attached shared budget, and returns a context carrying that attempt.
func WithBudgetScope ¶
WithBudgetScope attaches a custom budget scope without replacing an existing owner.
Types ¶
type Attempt ¶
type Attempt struct {
Ordinal uint64
Origin AttemptOrigin
ParentOrdinal uint64
StartedAt time.Time
}
Attempt describes one physical invocation within a logical execution.
func AttemptFromContext ¶
AttemptFromContext returns the physical attempt currently invoking work.
func NewAttempt ¶
func NewAttempt(ordinal uint64, origin AttemptOrigin, parent uint64, startedAt time.Time) (Attempt, error)
NewAttempt validates stable physical-attempt lineage.
type AttemptOrigin ¶
type AttemptOrigin string
AttemptOrigin identifies why physical work exists.
const ( // OriginOriginal identifies the first caller-requested operation. OriginOriginal AttemptOrigin = "original" // OriginRetry identifies sequential repeated work after a failure. OriginRetry AttemptOrigin = "retry" // OriginHedge identifies concurrent duplicate work for tail latency. OriginHedge AttemptOrigin = "hedge" )
type Budget ¶
type Budget struct {
// contains filtered or unexported fields
}
Budget owns process-local accounting shared by retry and hedge attempts.
Example ¶
clock := fixedExampleClock{}
budget, _ := resilience.NewBudget(resilience.BudgetConfig{
MaxResources: 16, MaxAdditionalPerExecution: 2,
MaxConcurrentAdditional: 1, MaxAdditionalPerWindow: 8,
AdditionalWindow: exampleDuration, PermitTTL: exampleDuration, Clock: clock,
})
metadata, _ := resilience.NewMetadata("request-1", "postal.lookup", "postal:FI")
scope, ctx, _ := budget.Start(context.Background(), metadata)
attempt, _ := resilience.NewAttempt(1, resilience.OriginOriginal, 0, clock.Now())
permit, _ := scope.Acquire(ctx, attempt)
_ = permit.Complete()
fmt.Println(scope.Snapshot().AdditionalAdmitted)
_ = scope.Close()
Output: 0
func NewBudget ¶
func NewBudget(config BudgetConfig) (*Budget, error)
NewBudget validates finite limits and constructs an empty process-local budget.
type BudgetConfig ¶
type BudgetConfig struct {
MaxResources int
MaxAdditionalPerExecution uint64
MaxConcurrentAdditional uint64
MaxAdditionalPerWindow uint64
AdditionalWindow time.Duration
PermitTTL time.Duration
Clock Clock
}
BudgetConfig defines finite process-local amplification limits.
type BudgetRejectionError ¶
type BudgetRejectionError struct {
Reason RejectionReason
Snapshot BudgetSnapshot
}
BudgetRejectionError reports local denial without classifying it as downstream failure.
func (*BudgetRejectionError) Error ¶
func (err *BudgetRejectionError) Error() string
func (*BudgetRejectionError) Unwrap ¶
func (err *BudgetRejectionError) Unwrap() error
type BudgetScope ¶
type BudgetScope struct {
// contains filtered or unexported fields
}
BudgetScope is the single retry-plus-hedge accounting owner for one logical execution.
func (*BudgetScope) Acquire ¶
Acquire atomically admits original, retry, or hedge work without waiting.
func (*BudgetScope) Close ¶
func (scope *BudgetScope) Close() error
Close rejects new work and releases resource identity after active permits settle.
func (*BudgetScope) Matches ¶
func (scope *BudgetScope) Matches(metadata Metadata) bool
Matches reports whether this scope owns the supplied immutable metadata.
func (*BudgetScope) Snapshot ¶
func (scope *BudgetScope) Snapshot() BudgetSnapshot
Snapshot reaps expired permits and returns bounded accounting state.
type BudgetSnapshot ¶
type BudgetSnapshot struct {
LogicalID string
Resource string
AdditionalAdmitted uint64
AdditionalActive uint64
AdditionalRecent uint64
Closed bool
}
BudgetSnapshot is an immutable bounded accounting view.
type ConfigurationError ¶
ConfigurationError identifies a public configuration field and safe reason.
func (*ConfigurationError) Error ¶
func (err *ConfigurationError) Error() string
func (*ConfigurationError) Unwrap ¶
func (err *ConfigurationError) Unwrap() error
type Event ¶
type Event struct {
Kind EventKind
Policy PolicyID
Reason string
LogicalID string
Attempt Attempt
At time.Time
}
Event contains only bounded metadata and never retains operation values.
type EventKind ¶
type EventKind string
EventKind identifies a bounded execution lifecycle event.
const ( // EventExecutionStarted identifies logical execution admission. EventExecutionStarted EventKind = "execution_started" // EventPolicyEntered identifies entry into one composed policy. EventPolicyEntered EventKind = "policy_entered" // EventWorkAdmitted identifies budget admission of physical work. EventWorkAdmitted EventKind = "work_admitted" // EventWorkRejected identifies local budget rejection. EventWorkRejected EventKind = "work_rejected" // EventAttemptStarted identifies invocation of physical work. EventAttemptStarted EventKind = "attempt_started" // EventAttemptCompleted identifies return from physical work. EventAttemptCompleted EventKind = "attempt_completed" // EventExecutionCanceled identifies caller cancellation of an execution. EventExecutionCanceled EventKind = "execution_canceled" // EventExecutionCompleted identifies the terminal logical outcome. EventExecutionCompleted EventKind = "execution_completed" )
type Execution ¶
type Execution struct {
Metadata Metadata
Attempt Attempt
// contains filtered or unexported fields
}
Execution is immutable call metadata passed through policy stages.
type Executor ¶
type Executor[T any] struct { // contains filtered or unexported fields }
Executor is an immutable, reusable policy composition.
Example ¶
package main
import (
"context"
"fmt"
"github.com/faustbrian/go-resilience"
)
func main() {
metadata, _ := resilience.NewMetadata("request-1", "postal.lookup", "postal:FI")
executor, _ := resilience.NewExecutor[string]()
result := executor.Execute(context.Background(), metadata,
func(_ context.Context, attempt resilience.Attempt) (string, error) {
return fmt.Sprintf("attempt-%d", attempt.Ordinal), nil
},
)
fmt.Println(result.Value, result.Outcome.Kind)
}
Output: attempt-1 success
func NewExecutor ¶
NewExecutor validates policies and composes them in outer-to-inner order.
func (Executor[T]) Execute ¶
func (executor Executor[T]) Execute(ctx context.Context, metadata Metadata, operation Operation[T]) (result Result[T])
Execute invokes synchronous work without creating an operation goroutine.
func (Executor[T]) Policies ¶
func (executor Executor[T]) Policies() []PolicyDescriptor
Policies returns a caller-owned copy in outer-to-inner order.
func (Executor[T]) WithClock ¶
WithClock returns a copy using clock for attempts and event timestamps.
func (Executor[T]) WithObserver ¶
WithObserver returns a copy that sends at most maxEvents retained events to observer.
type IgnoredError ¶
type IgnoredError struct{ Reason string }
IgnoredError carries only a bounded reason and no application value.
func (*IgnoredError) Error ¶
func (err *IgnoredError) Error() string
func (*IgnoredError) Unwrap ¶
func (err *IgnoredError) Unwrap() error
type LocalRejectionError ¶
LocalRejectionError carries bounded policy and reason identity with a safe cause.
func (*LocalRejectionError) Error ¶
func (err *LocalRejectionError) Error() string
func (*LocalRejectionError) Unwrap ¶
func (err *LocalRejectionError) Unwrap() []error
type Metadata ¶
type Metadata struct {
// contains filtered or unexported fields
}
Metadata is immutable logical-execution identity safe for bounded diagnostics.
func NewMetadata ¶
NewMetadata validates bounded, non-empty execution identifiers.
func (Metadata) LogicalID ¶
LogicalID returns the stable identity shared by all attempts in an execution.
type Observer ¶
type Observer interface {
Observe(Event)
}
Observer receives events after internal state changes and outside locks.
type ObserverFunc ¶
type ObserverFunc func(Event)
ObserverFunc adapts a function to Observer.
func (ObserverFunc) Observe ¶
func (function ObserverFunc) Observe(event Event)
Observe invokes the adapted function.
type Outcome ¶
type Outcome struct {
Kind OutcomeKind
Attempt Attempt
}
Outcome is the stable classification of a completed execution.
type OutcomeKind ¶
type OutcomeKind string
OutcomeKind classifies an execution without conflating local and downstream failures.
const ( // OutcomeSuccess identifies a completed operation without an error. OutcomeSuccess OutcomeKind = "success" // OutcomeOperationFailure identifies an error returned by downstream work. OutcomeOperationFailure OutcomeKind = "operation_failure" // OutcomeLocalRejection identifies work denied before downstream invocation. OutcomeLocalRejection OutcomeKind = "local_rejection" // OutcomeCancellation identifies cooperative caller cancellation. OutcomeCancellation OutcomeKind = "cancellation" // OutcomeDeadline identifies expiration of the caller-owned total deadline. OutcomeDeadline OutcomeKind = "deadline" // OutcomeIgnored identifies work intentionally omitted by a policy. OutcomeIgnored OutcomeKind = "ignored" // OutcomePolicyFailure identifies invalid or failed policy execution. OutcomePolicyFailure OutcomeKind = "policy_failure" )
type Permit ¶
type Permit interface {
Complete() error
}
Permit owns completion of one admitted physical attempt.
type Policy ¶
type Policy[T any] interface { Descriptor() PolicyDescriptor Wrap(Stage[T]) Stage[T] }
Policy wraps the next stage without hidden registration or discovery.
type PolicyDescriptor ¶
PolicyDescriptor makes ordering and execution scope inspectable.
type PolicyExecutionError ¶
PolicyExecutionError identifies the policy stage that failed safely.
func (*PolicyExecutionError) Error ¶
func (err *PolicyExecutionError) Error() string
func (*PolicyExecutionError) Unwrap ¶
func (err *PolicyExecutionError) Unwrap() []error
type PolicyID ¶
type PolicyID string
PolicyID is a bounded stable policy identity used by errors and diagnostics.
type RejectionReason ¶
type RejectionReason string
RejectionReason identifies the bounded admission rule that denied work.
const ( // ReasonExecutionLimit denies work after an execution exhausts its total allowance. ReasonExecutionLimit RejectionReason = "execution_limit" // ReasonConcurrentLimit denies work while the resource has no concurrent capacity. ReasonConcurrentLimit RejectionReason = "concurrent_limit" // ReasonWindowLimit denies work after the resource exhausts its rolling allowance. ReasonWindowLimit RejectionReason = "window_limit" // ReasonResourceLimit denies creation of a new bounded resource identity. ReasonResourceLimit RejectionReason = "resource_limit" // ReasonDuplicateWork denies a physical attempt already admitted by the scope. ReasonDuplicateWork RejectionReason = "duplicate_work" // ReasonOriginalRequired denies additional work before the original attempt. ReasonOriginalRequired RejectionReason = "original_required" // ReasonUnknownParent denies additional work whose parent was never admitted. ReasonUnknownParent RejectionReason = "unknown_parent" )
func RejectionReasonOf ¶
func RejectionReasonOf(err error) RejectionReason
RejectionReasonOf extracts a bounded reason or returns the empty value.
type Result ¶
Result preserves the typed operation value, original error, bounded events, and outcome.
func LocalRejection ¶
LocalRejection constructs a local denial that remains distinct from operation failure.
func PolicyFailure ¶
PolicyFailure constructs a failure owned by policy logic.
type WorkBudget ¶
type WorkBudget interface {
Start(context.Context, Metadata) (WorkBudgetScope, context.Context, error)
}
WorkBudget is the shared admission contract consumed by retry and hedge policies.
type WorkBudgetScope ¶
type WorkBudgetScope interface {
Acquire(context.Context, Attempt) (Permit, error)
Snapshot() BudgetSnapshot
Matches(Metadata) bool
Close() error
}
WorkBudgetScope owns all physical work for one logical execution.
func BudgetScopeFromContext ¶
func BudgetScopeFromContext(ctx context.Context) (WorkBudgetScope, bool)
BudgetScopeFromContext returns the explicitly attached logical budget scope.
type WorkPermit ¶
type WorkPermit struct {
// contains filtered or unexported fields
}
WorkPermit owns exactly one admitted physical-work lifecycle.
func (*WorkPermit) Complete ¶
func (permit *WorkPermit) Complete() error
Complete releases concurrent capacity exactly once.