failsafe

package module
v0.0.0-...-d45231a Latest Latest
Warning

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

Go to latest
Published: Nov 1, 2023 License: Apache-2.0 Imports: 7 Imported by: 0

README

Failsafe-go

Build Status Go Report Card License Slack Godoc

Failsafe-go is a library for building fault tolerant Go applications. It works by wrapping executable logic with one or more resilience policies, which can be combined and composed as needed.

Policies include Retry, CircuitBreaker, RateLimiter, Timeout, Bulkhead, and Fallback.

Usage

Visit failsafe-go.dev for usage info, docs, and additional resources.

Contributing

Check out the contributing guidelines.

License

Copyright Jonathan Halterman and friends. Released under the Apache 2.0 license.

Documentation

Overview

Package failsafe provides the entrypoint for using Failsafe-go.

Failsafe-go adds fault tolerance to function execution. Functions can be wrapped with one or more resilience policies, for example:

result, err := failsafe.Get(fn, retryPolicy)

When multiple policies are provided, are composed around the fn and will handle its results in reverse order. For example, consider:

failsafe.Get(fn, fallback, retryPolicy, circuitBreaker)

This creates the following composition when executing the fn and handling its result:

Fallback(RetryPolicy(CircuitBreaker(fn)))

Index

Constants

This section is empty.

Variables

View Source
var ErrExecutionCanceled = errors.New("execution canceled")

ErrExecutionCanceled indicates that an execution was canceled by ExecutionResult.Cancel.

Functions

func Get

func Get[R any](fn func() (R, error), policies ...Policy[R]) (R, error)

Get executes the fn, with failures being handled by the policies, until a successful result is returned or the policies are exceeded.

func GetWithExecution

func GetWithExecution[R any](fn func(exec Execution[R]) (R, error), policies ...Policy[R]) (R, error)

GetWithExecution executes the fn, with failures being handled by the policies, until a successful result is returned or the policies are exceeded.

func Run

func Run(fn func() error, policies ...Policy[any]) error

Run executes the fn, with failures being handled by the policies, until successful or until the policies are exceeded.

func RunWithExecution

func RunWithExecution(fn func(exec Execution[any]) error, policies ...Policy[any]) error

RunWithExecution executes the fn, with failures being handled by the policies, until successful or until the policies are exceeded.

Types

type DelayFunc

type DelayFunc[R any] func(exec ExecutionAttempt[R]) time.Duration

DelayFunc returns a duration to delay for given the ExecutionAttempt.

type DelayablePolicyBuilder

type DelayablePolicyBuilder[S any, R any] interface {
	// WithDelay configures the time to delay between execution attempts.
	WithDelay(delay time.Duration) S

	// WithDelayFunc accepts a function that configures the time to delay before the next execution attempt.
	WithDelayFunc(delayFn DelayFunc[R]) S
}

DelayablePolicyBuilder builds policies that can be delayed between executions.

type Execution

type Execution[R any] interface {
	ExecutionAttempt[R]

	// Context returns the context configured for the execution, else nil if none is configured. For executions that may
	// timeout, each attempt will get a separate child context.
	Context() context.Context

	// IsCanceled returns whether the execution has been canceled by an external Context or a timeout.Timeout.
	IsCanceled() bool

	// Canceled returns a channel that is closed when the execution is canceled, either by an external Context or a
	// timeout.Timeout.
	Canceled() <-chan any
}

Execution contains information about an execution.

type ExecutionAttempt

type ExecutionAttempt[R any] interface {
	ExecutionStats

	// LastResult returns the result, if any, from the last execution attempt.
	LastResult() R

	// LastError returns the error, if any, from the last execution attempt.
	LastError() error

	// IsFirstAttempt returns true when Attempts is 1, meaning this is the first execution attempt.
	IsFirstAttempt() bool

	// IsRetry returns true when Attempts is > 1, meaning the execution is being retried.
	IsRetry() bool

	// AttemptStartTime returns the time that the most recent execution attempt started at.
	AttemptStartTime() time.Time

	// ElapsedAttemptTime returns the elapsed time since the last execution attempt began.
	ElapsedAttemptTime() time.Duration
}

ExecutionAttempt contains information for an execution attempt.

type ExecutionDoneEvent

type ExecutionDoneEvent[R any] struct {
	ExecutionStats
	// The execution result, else the zero value for R
	Result R
	// The execution error, else nil
	Error error
}

ExecutionDoneEvent indicates an execution is done.

type ExecutionEvent

type ExecutionEvent[R any] struct {
	ExecutionAttempt[R]
}

ExecutionEvent indicates an execution was attempted.

type ExecutionResult

type ExecutionResult[R any] interface {
	// Done is a channel that is closed when the execution is done and the result can be retrieved via Get, Result, or Error.
	Done() <-chan any

	// IsDone returns whether the execution is done and the result can be retrieved via Get.
	IsDone() bool

	// Get returns the execution result and error, else the default values, blocking until the execution is done.
	Get() (R, error)

	// Result returns the execution result else its default value, blocking until the execution is done.
	Result() R

	// Error returns the execution error else nil, blocking until the execution is done.
	Error() error

	// Cancel cancels the execution if it is not already done, with ErrExecutionCanceled as the error. If a Context was
	// configured with the execution, a child context will be created for the execution and canceled as well.
	Cancel()
}

ExecutionResult provides the result of an asynchronous execution.

func GetAsync

func GetAsync[R any](fn func() (R, error), policies ...Policy[R]) ExecutionResult[R]

GetAsync executes the fn in a goroutine, with failures being handled by the policies, until a successful result is returned or the policies are exceeded.

func GetWithExecutionAsync

func GetWithExecutionAsync[R any](fn func(exec Execution[R]) (R, error), policies ...Policy[R]) ExecutionResult[R]

GetWithExecutionAsync executes the fn in a goroutine, with failures being handled by the policies, until a successful result is returned or the policies are exceeded.

func RunAsync

func RunAsync(fn func() error, policies ...Policy[any]) ExecutionResult[any]

RunAsync executes the fn in a goroutine, with failures being handled by the policies, until successful or until the policies are exceeded.

func RunWithExecutionAsync

func RunWithExecutionAsync(fn func(exec Execution[any]) error, policies ...Policy[any]) ExecutionResult[any]

RunWithExecutionAsync executes the fn in a goroutine, with failures being handled by the policies, until successful or until the policies are exceeded.

type ExecutionScheduledEvent

type ExecutionScheduledEvent[R any] struct {
	ExecutionAttempt[R]
	// The delay before the next execution attempt.
	Delay time.Duration
}

ExecutionScheduledEvent indicates an execution was scheduled.

type ExecutionStats

type ExecutionStats interface {
	// Attempts returns the number of execution attempts so far, including attempts that are currently in progress and
	// attempts that were blocked before being executed, such as by a CircuitBreaker or RateLimiter.
	Attempts() int

	// Executions returns the number of completed executions. Executions that are blocked, such as when a CircuitBreaker is
	// open, are not counted.
	Executions() int

	// StartTime returns the time that the initial execution attempt started at.
	StartTime() time.Time

	// ElapsedTime returns the elapsed time since initial execution attempt began.
	ElapsedTime() time.Duration
}

ExecutionStats contains execution stats.

type Executor

type Executor[R any] interface {
	// WithContext returns a new copy of the Executor with the ctx configured. Any executions created with the resulting
	// Executor will be canceled when the ctx is done. Executions can cooperate with cancellation by checking
	// Execution.Canceled or Execution.IsCanceled.
	WithContext(ctx context.Context) Executor[R]

	// OnDone registers the listener to be called when an execution is done.
	OnDone(listener func(ExecutionDoneEvent[R])) Executor[R]

	// OnSuccess registers the listener to be called when an execution is successful. If multiple policies, are configured,
	// this handler is called when execution is done and all policies succeed. If all policies do not succeed, then the
	// OnFailure registered listener is called instead.
	OnSuccess(listener func(ExecutionDoneEvent[R])) Executor[R]

	// OnFailure registers the listener to be called when an execution fails. This occurs when the execution fails according
	// to some policy, and all policies have been exceeded.
	OnFailure(listener func(ExecutionDoneEvent[R])) Executor[R]

	// Run executes the fn until successful or until the configured policies are exceeded.
	//
	// Any panic causes the execution to stop immediately without calling any event listeners.
	Run(fn func() error) error

	// RunWithExecution executes the fn until successful or until the configured policies are exceeded, while providing an
	// Execution to the fn.
	//
	// Any panic causes the execution to stop immediately without calling any event listeners.
	RunWithExecution(fn func(exec Execution[R]) error) error

	// Get executes the fn until a successful result is returned or the configured policies are exceeded.
	//
	// Any panic causes the execution to stop immediately without calling any event listeners.
	Get(fn func() (R, error)) (R, error)

	// GetWithExecution executes the fn until a successful result is returned or the configured policies are exceeded, while
	// providing an Execution to the fn.
	//
	// Any panic causes the execution to stop immediately without calling any event listeners.
	GetWithExecution(fn func(exec Execution[R]) (R, error)) (R, error)

	// RunAsync executes the fn in a goroutine until successful or until the configured policies are exceeded.
	//
	// Any panic causes the execution to stop immediately without calling any event listeners.
	RunAsync(fn func() error) ExecutionResult[R]

	// RunWithExecutionAsync executes the fn in a goroutine until successful or until the configured policies are exceeded,
	// while providing an Execution to the fn.
	//
	// Any panic causes the execution to stop immediately without calling any event listeners.
	RunWithExecutionAsync(fn func(exec Execution[R]) error) ExecutionResult[R]

	// GetAsync executes the fn in a goroutine until a successful result is returned or the configured policies are exceeded.
	//
	// Any panic causes the execution to stop immediately without calling any event listeners.
	GetAsync(fn func() (R, error)) ExecutionResult[R]

	// GetWithExecutionAsync executes the fn in a goroutine until a successful result is returned or the configured policies
	// are exceeded, while providing an Execution to the fn.
	//
	// Any panic causes the execution to stop immediately without calling any event listeners.
	GetWithExecutionAsync(fn func(exec Execution[R]) (R, error)) ExecutionResult[R]
}

Executor handles failures according to configured policies. See NewExecutor for details.

This type is concurrency safe.

func NewExecutor

func NewExecutor[R any](policies ...Policy[R]) Executor[R]

NewExecutor creates and returns a new Executor for result type R that will handle failures according to the given policies. The policies are composed around a func and will handle its results in reverse order. For example, consider:

failsafe.NewExecutor(fallback, retryPolicy, circuitBreaker).Get(fn)

This creates the following composition when executing a func and handling its result:

Fallback(RetryPolicy(CircuitBreaker(func)))

type FailurePolicyBuilder

type FailurePolicyBuilder[S any, R any] interface {
	// HandleErrors specifies the errors to handle as failures. Any errors that evaluate to true for errors.Is and the
	// execution error will be handled.
	HandleErrors(errors ...error) S

	// HandleResult specifies the results to handle as failures. Any result that evaluates to true for reflect.DeepEqual and
	// the execution result will be handled. This method is only considered when a result is returned from an execution, not
	// when an error is returned.
	HandleResult(result R) S

	// HandleIf specifies that a failure has occurred if the predicate matches the execution result or error.
	HandleIf(predicate func(R, error) bool) S

	// OnSuccess registers the listener to be called when the policy determines an execution attempt was a success.
	OnSuccess(listener func(ExecutionEvent[R])) S

	// OnFailure registers the listener to be called when the policy determines an execution attempt was a failure, and may
	// be handled.
	OnFailure(listener func(ExecutionEvent[R])) S
}

FailurePolicyBuilder builds a Policy that allows configurable conditions to determine whether an execution is a failure.

  • By default, any error is considered a failure and will be handled by the policy. You can override this by specifying your own handle conditions. The default error handling condition will only be overridden by another condition that handles errors such as Handle or HandleIf. Specifying a condition that only handles results, such as HandleResult will not replace the default error handling condition.
  • If multiple handle conditions are specified, any condition that matches an execution result or error will trigger policy handling.

type Policy

type Policy[R any] interface {
	// ToExecutor returns a policy.Executor capable of handling an execution for the Policy.
	// The typeToken parameter helps catch mismatches between R types when composing policies.
	ToExecutor(policyIndex int, typeToken R) any
}

Policy handles execution failures.

Directories

Path Synopsis
Package bulkhead provides a Bulkhead policy.
Package bulkhead provides a Bulkhead policy.
Package circuitbreaker provides a CircuitBreaker policy.
Package circuitbreaker provides a CircuitBreaker policy.
Package common contains types that are common to the failsafe and policy packages.
Package common contains types that are common to the failsafe and policy packages.
Package fallback provides a Fallback policy.
Package fallback provides a Fallback policy.
policytesting
Package policytesting is needed to avoid a circular dependency with the policy package.
Package policytesting is needed to avoid a circular dependency with the policy package.
Package policy provides types that are used for implementing a failsafe.Policy.
Package policy provides types that are used for implementing a failsafe.Policy.
Package ratelimiter provides a RateLimiter policy.
Package ratelimiter provides a RateLimiter policy.
Package retrypolicy provides a RetryPolicy.
Package retrypolicy provides a RetryPolicy.
Package timeout provides a Timeout policy.
Package timeout provides a Timeout policy.

Jump to

Keyboard shortcuts

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