Documentation
¶
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var DefaultBackoff = Backoff{ Base: 100 * time.Millisecond, Max: 30 * time.Second, Multiplier: 2.0, Jitter: true, }
DefaultBackoff is a sensible starting point for most use cases.
var DefaultRetry = RetryConfig{ MaxAttempts: 3, Backoff: DefaultBackoff, }
DefaultRetry is a sensible starting point.
var ErrCircuitOpen = vortex.ErrCircuitOpen
Functions ¶
func IsRetryable ¶ added in v0.1.8
IsRetryable reports whether err is a RetryableError.
func Retry ¶
Retry calls fn repeatedly until it succeeds or runs out of attempts. fn receives the current attempt number starting at 0. Only errors wrapped with Retryable() are retried — all other errors stop retrying immediately and are returned as-is.
example:
err := resilience.Retry(ctx, resilience.DefaultRetry, func(attempt int) error {
if err := callAPI(); err != nil {
if isTransient(err) {
return resilience.Retryable(err) // retry this
}
return err // stop immediately — not retryable
}
return nil
})
Example ¶
package main
import (
"context"
"errors"
"fmt"
"github.com/MostafaMagdSalama/vortex/resilience"
)
func main() {
// A simulated API call that fails once before succeeding.
failures := 0
callAPI := func() error {
if failures < 1 {
failures++
return errors.New("temporary network error")
}
return nil
}
// Retry executes the function until it succeeds or MaxAttempts is reached.
// Only errors wrapped in resilience.Retryable() are retried.
err := resilience.Retry(context.Background(), resilience.DefaultRetry, func(attempt int) error {
fmt.Printf("Attempt %d...\n", attempt)
if err := callAPI(); err != nil {
// Wrap the error to tell Retry that this is a transient failure.
return resilience.Retryable(err)
}
fmt.Println("Success!")
return nil
})
if err != nil {
fmt.Println("Final Error:", err)
}
}
Output: Attempt 0... Attempt 1... Success!
Types ¶
type CircuitBreaker ¶
type CircuitBreaker struct {
// contains filtered or unexported fields
}
CircuitBreaker stops calling a failing service to give it time to recover.
Example ¶
package main
import (
"context"
"errors"
"fmt"
"time"
"github.com/MostafaMagdSalama/vortex"
"github.com/MostafaMagdSalama/vortex/resilience"
)
func main() {
// Create a CircuitBreaker that opens after 2 consecutive failures
// and waits 100 milliseconds before allowing a trial request (Half-Open).
cb := resilience.NewCircuitBreaker(2, 100*time.Millisecond)
// A simulated failing API
failingAPI := func(ctx context.Context) error {
return errors.New("500 Internal Server Error")
}
// 1. First failure
_ = cb.Execute(context.Background(), failingAPI)
// 2. Second failure - The circuit now trips to "Open"
_ = cb.Execute(context.Background(), failingAPI)
// 3. Third request - Rejected immediately without calling the API
err := cb.Execute(context.Background(), failingAPI)
if errors.Is(err, vortex.ErrCircuitOpen) {
fmt.Println("Circuit is open! Falling back to cache.")
}
}
Output: Circuit is open! Falling back to cache.
func NewCircuitBreaker ¶
func NewCircuitBreaker(maxFailures int, timeout time.Duration) *CircuitBreaker
NewCircuitBreaker creates a breaker that opens after maxFailures consecutive failures and tries again after timeout.
func (*CircuitBreaker) Execute ¶
Execute runs fn if the circuit allows it. ctx is passed to fn so the call can be cancelled. In half-open state only one trial request is allowed at a time.
example:
err := cb.Execute(ctx, func(ctx context.Context) error {
return callAPI(ctx)
})
if errors.Is(err, resilience.ErrCircuitOpen) {
// serve from cache instead
}
func (*CircuitBreaker) State ¶ added in v0.1.8
func (cb *CircuitBreaker) State() CircuitState
State returns the current state of the breaker.
func (*CircuitBreaker) Stats ¶ added in v0.1.8
func (cb *CircuitBreaker) Stats() Stats
Stats returns a snapshot of the breaker's runtime metrics.
type CircuitState ¶ added in v0.1.8
type CircuitState int
CircuitState represents the current state of a CircuitBreaker.
const ( StateClosed CircuitState = iota // normal — requests go through StateOpen // tripped — requests blocked StateHalfOpen // testing — one request allowed )
func (CircuitState) String ¶ added in v0.1.8
func (s CircuitState) String() string
type RetryConfig ¶
RetryConfig controls how retries behave.
type RetryableError ¶ added in v0.1.8
type RetryableError struct {
Err error
}
RetryableError wraps an error and signals that the operation can be retried. Use Retryable() to wrap errors that should be retried and return unwrapped errors for failures that should stop retrying immediately.
func (RetryableError) Error ¶ added in v0.1.8
func (e RetryableError) Error() string
func (RetryableError) Unwrap ¶ added in v0.1.8
func (e RetryableError) Unwrap() error
type Stats ¶ added in v0.1.8
type Stats struct {
Requests int64 // total calls to Execute
Failures int64 // calls where fn returned an error
Successes int64 // calls where fn returned nil
Rejected int64 // calls rejected because circuit was open
State CircuitState // current state of the breaker
}
Stats holds runtime metrics for a CircuitBreaker.