Documentation ¶
Index ¶
- Variables
- func Cancel(ctx context.Context) context.CancelCauseFunc
- func FixedWindow(count int, d time.Duration) func() (bool, time.Duration)
- func IsEnd(f Fn) bool
- func IsError(f Fn) bool
- func Run(ctx context.Context, states ...Fn) error
- func RunParallel(ctx context.Context, states ...Fn) error
- type ErrorFn
- type Fn
- func After(d time.Duration, state Fn) Fn
- func At(t time.Time, state Fn) Fn
- func BackOff(dur StrategyFn, fn Fn) Fn
- func Batch(states ...Fn) Fn
- func Breaker(trip TripStrategyFn, fn Fn) Fn
- func ErrorEnd(err error) Fn
- func ErrorRestart(err error) Fn
- func NonBlocking(states ...Fn) Fn
- func OpenBreaker() Fn
- func Parallel(states ...Fn) Fn
- func RateLimit(limitFn LimitStrategyFn, states ...Fn) Fn
- func Retry(count int, fn Fn) Fn
- func StartState(ctx context.Context) Fn
- func Timeout(max time.Duration, state Fn) Fn
- func TimeoutExceeded() Fn
- func Wrap(fn func(ctx context.Context) error) Fn
- func WrapRepeat(fn func(ctx context.Context) error) Fn
- type LimitStrategyFn
- type StrategyFn
- type TripStrategyFn
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var InvalidRateLimitFn = errors.New("invalid rate limit method")
Functions ¶
Types ¶
type Fn ¶
func After ¶
After runs the received state after d time.Duration has elapsed. This function blocks until the timer elapses, when it returns the next resolved state.
func At ¶
At runs the received state at t time.Time. This function blocks until the time is reached, when it returns the next resolved state.
func BackOff ¶
func BackOff(dur StrategyFn, fn Fn) Fn
BackOff returns an aggregator function which can be used to execute the received state with increasing delays. The function for determining the delay is passed in the StrategyFn "dur" parameter.
There is no end condition, so take care to limit the execution through some external method.
func Batch ¶
Batch executes the received states sequentially, and accumulates the next states. The resulting next state is returned as a sequential batch of all the non End states resolved.
func Breaker ¶
func Breaker(trip TripStrategyFn, fn Fn) Fn
Breaker is a state machine that can be used for disabling execution of incoming "fn" state if its returning state is an error state and the conditions of the "trip" TripStrategyFn are fulfilled.
Currently, there is no method for closing the Breaker once opened.
func ErrorRestart ¶
ErrorRestart represents an error state which returns the first iteration passed. This iteration is loaded from the context, and is saved there by the Run and RunParallel functions.
func NonBlocking ¶
NonBlocking executes states in a goroutine and until it resolves it returns a wait state
func OpenBreaker ¶
func OpenBreaker() Fn
OpenBreaker is an error state that is used to trip open the Breaker.
func Parallel ¶
Parallel executes the received states in parallel goroutines, and accumulates the next states. The resulting next state is returned as a parallel batch of all the non End states resolved.
func RateLimit ¶
func RateLimit(limitFn LimitStrategyFn, states ...Fn) Fn
RateLimit is a state machine that executes the "state" Fn under the constraints of the "limitFn" LimitStrategyFn.
The strategy function returns if the current execution needs to be stalled in order to fulfill the rate limit logic it corresponds to, together with what the corresponding delay should be, if it does.
func Retry ¶
Retry is a way to construct a state machine out of repeating the execution of received state "fn", when it returns an IsError state until the number of "retries" has been reached.
The "fn" parameter can be one of the functions accepting a StrategyFn parameters, which wrap the original state Fn, and which provide a way to delay the execution between retries.
The Retry state machine is reentrant, therefore can be used from multiple goroutines.
Example ¶
package main import ( "context" "fmt" "time" sm "git.sr.ht/~mariusor/ssm" ) func main() { st := time.Now() cnt := 0 fmt.Printf("Retries\n") retry := sm.Retry(10, func(_ context.Context) sm.Fn { cnt++ run := time.Now() fmt.Printf("%d:%s\n", cnt, run.Sub(st).Truncate(time.Millisecond)) st = run return sm.ErrorEnd(fmt.Errorf("retrying")) }) sm.Run(context.Background(), retry) }
Output: Retries 1:0s 2:0s 3:0s 4:0s 5:0s 6:0s 7:0s 8:0s 9:0s 10:0s
func StartState ¶
StartState retrieves the initial state from ctx context.Context. If nothing is found it returns the End state.
func Timeout ¶
Timeout is a state machine that calls the "state" Fn limiting its execution time to a maximum of "max" time.Duration.
If the timeout is reached, the execution is canceled and an ErrorEnd state wrapping the context.DeadlineExceeded error is returned.
func TimeoutExceeded ¶
func TimeoutExceeded() Fn
TimeoutExceeded is an error state that is used when a Timeout is reached.
type LimitStrategyFn ¶
LimitStrategyFn are a type of functions that determine if successive calls to a RateLimit'ed state require stalling and how much stalling is required to fulfill the desired rate limit.
type StrategyFn ¶
StrategyFn is the type that returns the desired time.Duration for the BackOff function.
func Constant ¶
func Constant(d time.Duration) StrategyFn
Constant returns a constant time.Duration for every call.
Example ¶
package main import ( "context" "fmt" "time" sm "git.sr.ht/~mariusor/ssm" ) const delay = 10 * time.Millisecond func main() { st := time.Now() cnt := 0 fmt.Printf("8 retries with constant backoff of 10ms\n") con := sm.Retry(8, sm.BackOff(sm.Constant(delay), func(_ context.Context) sm.Fn { run := time.Now() cnt++ fmt.Printf("%d:%s\n", cnt, run.Sub(st).Truncate(delay)) st = run return sm.ErrorEnd(fmt.Errorf("keep going")) })) sm.Run(context.Background(), con) }
Output: 8 retries with constant backoff of 10ms 1:10ms 2:10ms 3:10ms 4:10ms 5:10ms 6:10ms 7:10ms 8:10ms
func Jitter ¶
func Jitter(max time.Duration, fn StrategyFn) StrategyFn
Jitter adds random jitter of "max" time.Duration for the fn StrategyFn
Example ¶
package main import ( "context" "fmt" "time" sm "git.sr.ht/~mariusor/ssm" ) const delay = 10 * time.Millisecond func main() { st := time.Now() cnt := 0 fmt.Printf("2 retries with 1ms jitter over 10ms delay\n") jitter := sm.Retry(2, sm.BackOff(sm.Jitter(time.Millisecond, sm.Constant(delay)), func(_ context.Context) sm.Fn { run := time.Now() cnt++ // NOTE(marius): The jitter adds a maximum of 1 ms, so with truncation of 2 ms the output will be correct // This is not a very good example test, though. fmt.Printf("%d:%s\n", cnt, run.Sub(st).Truncate(2*time.Millisecond)) st = run return sm.ErrorEnd(fmt.Errorf("never right")) })) sm.Run(context.Background(), jitter) }
Output: 2 retries with 1ms jitter over 10ms delay 1:10ms 2:10ms
func Linear ¶
func Linear(d time.Duration, m float64) StrategyFn
Linear returns the linear function of the time.Duration multiplied by mul for every call.
Example ¶
package main import ( "context" "fmt" "time" sm "git.sr.ht/~mariusor/ssm" ) const delay = 10 * time.Millisecond func main() { st := time.Now() cnt := 0 fmt.Printf("5 retries with 2x linear backoff 10ms delay\n") linear := sm.Retry(5, sm.BackOff(sm.Linear(delay, 2), func(_ context.Context) sm.Fn { run := time.Now() cnt++ fmt.Printf("%d:%s\n", cnt, run.Sub(st).Truncate(delay)) st = run return sm.ErrorEnd(fmt.Errorf("don't stop")) })) sm.Run(context.Background(), linear) }
Output: 5 retries with 2x linear backoff 10ms delay 1:10ms 2:20ms 3:40ms 4:80ms 5:160ms
type TripStrategyFn ¶
type TripStrategyFn func() bool
TripStrategyFn is used by the Circuit Breaker state machine to determine if current run requires the breaker to trip open.
Our API doesn't allow these functions to do the error check on the returned state of the breaker state. It is assumed that the Breaker itself calls the TripStrategyFn function only for error states.
func MaxTriesTrip ¶
func MaxTriesTrip(max int) TripStrategyFn
MaxTriesTrip returns false for "max" invocations, then returns true. It is the simplest form of count based circuit breaking.
The check function itself can be run safely in parallel, so if multiple checks are needed, MaxTriesTrip must be invoked multiple times.
func TimedTrip ¶
func TimedTrip(d time.Duration, fn TripStrategyFn) TripStrategyFn
TimedTrip uses "fn" TripStrategyFn for returning the status of the Breaker, but it resets it every "d" time.Duration.