Documentation
¶
Overview ¶
Package resilience provides error handling, retry logic, and backoff strategies for building resilient voice applications.
The package is designed to work with the AX (Agent Experience) specification, enabling intelligent error recovery based on error categorization.
Error Categories ¶
Errors are classified into categories that determine handling strategy:
- CategoryTransient: Temporary failures, retry with backoff
- CategoryRateLimit: Rate limited, retry with longer backoff
- CategoryValidation: Invalid input, don't retry
- CategoryAuth: Authentication failure, don't retry
- CategoryNotFound: Resource not found, don't retry
- CategoryServer: Server error, retry with backoff
- CategoryQuota: Quota exceeded, don't retry
- CategoryUnknown: Unknown error, use default behavior
Retry Logic ¶
The Retry and RetryWithResult functions execute operations with automatic retries for retryable errors:
result, err := resilience.RetryWithResult(ctx, resilience.DefaultRetryConfig(), func() (string, error) {
return api.Call()
})
Backoff Strategies ¶
ExponentialBackoff provides exponential backoff with jitter:
backoff := &resilience.ExponentialBackoff{
Initial: time.Second,
Max: 30 * time.Second,
Multiplier: 2.0,
Jitter: 0.1,
}
Error Wrapping ¶
ProviderError wraps provider errors with AX metadata:
err := &resilience.ProviderError{
Provider: "elevenlabs",
Op: "Synthesize",
Err: originalErr,
Info: resilience.ErrorInfo{
Category: resilience.CategoryRateLimit,
Retryable: true,
Code: "RATE_LIMITED",
Suggestion: "Wait and retry with exponential backoff",
},
}
Index ¶
- func Do(ctx context.Context, fn func() error) error
- func DoWithResult[T any](ctx context.Context, fn func() (T, error)) (T, error)
- func GetRetryAfter(err error) time.Duration
- func IsRetryable(err error) bool
- func Retry(ctx context.Context, config RetryConfig, fn func() error) error
- func RetryWithResult[T any](ctx context.Context, config RetryConfig, fn func() (T, error)) (T, error)
- type BackoffStrategy
- type ConstantBackoff
- type DefaultClassifier
- type ErrorCategory
- type ErrorClassifier
- type ErrorInfo
- type ExponentialBackoff
- type HTTPStatusClassifier
- type LinearBackoff
- type NoBackoff
- type ProviderError
- func (e *ProviderError) Error() string
- func (e *ProviderError) GetCategory() ErrorCategory
- func (e *ProviderError) GetCode() string
- func (e *ProviderError) GetRetryAfter() time.Duration
- func (e *ProviderError) GetSuggestion() string
- func (e *ProviderError) Is(target error) bool
- func (e *ProviderError) IsRetryable() bool
- func (e *ProviderError) Unwrap() error
- type RetryConfig
- type RetryError
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func DoWithResult ¶
DoWithResult is a convenience wrapper for RetryWithResult with default config.
func GetRetryAfter ¶
GetRetryAfter extracts retry-after duration from an error. Returns zero if not a ProviderError or no retry-after specified.
func IsRetryable ¶
IsRetryable checks if an error should be retried.
func Retry ¶
func Retry(ctx context.Context, config RetryConfig, fn func() error) error
Retry executes fn with retries according to config.
It returns nil on success, or the last error after all retries are exhausted. If the context is canceled, it returns the context error immediately.
Example:
err := resilience.Retry(ctx, resilience.DefaultRetryConfig(), func() error {
return api.Call()
})
func RetryWithResult ¶
func RetryWithResult[T any](ctx context.Context, config RetryConfig, fn func() (T, error)) (T, error)
RetryWithResult executes fn with retries and returns the result on success.
Example:
result, err := resilience.RetryWithResult(ctx, config, func() (string, error) {
return api.GetValue()
})
Types ¶
type BackoffStrategy ¶
type BackoffStrategy interface {
// NextDelay returns the delay before the next retry attempt.
// attempt is 1-indexed (first retry is attempt 1).
NextDelay(attempt int) time.Duration
// Reset resets the backoff state for a new operation.
Reset()
}
BackoffStrategy computes delay between retries.
func DefaultBackoff ¶
func DefaultBackoff() BackoffStrategy
DefaultBackoff returns a sensible default exponential backoff strategy.
type ConstantBackoff ¶
ConstantBackoff always returns the same delay.
func (*ConstantBackoff) NextDelay ¶
func (b *ConstantBackoff) NextDelay(attempt int) time.Duration
NextDelay returns the constant delay.
func (*ConstantBackoff) Reset ¶
func (b *ConstantBackoff) Reset()
Reset resets the backoff state (no-op for stateless implementation).
type DefaultClassifier ¶
type DefaultClassifier struct{}
DefaultClassifier provides basic error classification based on common patterns. Use this as a fallback when no provider-specific classifier is available.
func (*DefaultClassifier) Classify ¶
func (c *DefaultClassifier) Classify(err error) ErrorInfo
Classify categorizes an error using common heuristics.
type ErrorCategory ¶
type ErrorCategory string
ErrorCategory classifies errors for handling decisions.
const ( // CategoryTransient indicates a temporary failure that may succeed on retry. // Examples: network timeout, connection reset. CategoryTransient ErrorCategory = "transient" // CategoryRateLimit indicates the request was rate limited. // Retry with longer backoff, respect Retry-After header if present. CategoryRateLimit ErrorCategory = "rate_limit" // CategoryValidation indicates invalid input that will never succeed. // Do not retry; fix the request first. CategoryValidation ErrorCategory = "validation" // CategoryAuth indicates an authentication or authorization failure. // Do not retry; re-authenticate or check permissions. CategoryAuth ErrorCategory = "auth" // CategoryNotFound indicates the requested resource does not exist. // Do not retry; the resource must be created first. CategoryNotFound ErrorCategory = "not_found" // CategoryServer indicates an internal server error. // May succeed on retry; use exponential backoff. CategoryServer ErrorCategory = "server" // CategoryQuota indicates a quota or limit has been exceeded. // Do not retry; quota must be increased or reset. CategoryQuota ErrorCategory = "quota" // CategoryUnknown indicates the error could not be classified. // Use default behavior (typically no retry). CategoryUnknown ErrorCategory = "unknown" )
func (ErrorCategory) IsRetryable ¶
func (c ErrorCategory) IsRetryable() bool
IsRetryable returns true if errors in this category should typically be retried.
func (ErrorCategory) String ¶
func (c ErrorCategory) String() string
String returns the string representation of the category.
func (ErrorCategory) SuggestedAction ¶
func (c ErrorCategory) SuggestedAction() string
SuggestedAction returns a human-readable suggestion for handling this category.
type ErrorClassifier ¶
type ErrorClassifier interface {
// Classify analyzes an error and returns its metadata.
Classify(err error) ErrorInfo
}
ErrorClassifier categorizes errors from any source. Implementations should be provider-specific.
type ErrorInfo ¶
type ErrorInfo struct {
// Category classifies the error for handling decisions.
Category ErrorCategory
// Retryable indicates if the operation can be safely retried.
Retryable bool
// Code is a machine-readable error code (e.g., "RATE_LIMITED").
Code string
// Message is a human-readable error description.
Message string
// Suggestion provides guidance for error recovery.
Suggestion string
// RetryAfter hints how long to wait before retrying.
// Zero means use default backoff strategy.
RetryAfter time.Duration
}
ErrorInfo provides actionable metadata about an error.
func GetErrorInfo ¶
GetErrorInfo extracts ErrorInfo from an error. If the error is not a ProviderError, returns an unknown category.
type ExponentialBackoff ¶
type ExponentialBackoff struct {
// Initial is the delay for the first retry (default: 1s).
Initial time.Duration
// Max is the maximum delay (default: 30s).
Max time.Duration
// Multiplier is the factor by which delay increases (default: 2.0).
Multiplier float64
// Jitter is the random factor applied to delays (0-1, default: 0.1).
// A jitter of 0.1 means ±10% randomization.
Jitter float64
}
ExponentialBackoff implements exponential backoff with optional jitter.
The delay for attempt n is: min(Initial * Multiplier^(n-1) * (1 ± Jitter), Max)
Example with Initial=1s, Multiplier=2, Max=30s:
- Attempt 1: 1s
- Attempt 2: 2s
- Attempt 3: 4s
- Attempt 4: 8s
- Attempt 5: 16s
- Attempt 6+: 30s (capped)
func (*ExponentialBackoff) NextDelay ¶
func (b *ExponentialBackoff) NextDelay(attempt int) time.Duration
NextDelay returns the delay before the next retry attempt.
func (*ExponentialBackoff) Reset ¶
func (b *ExponentialBackoff) Reset()
Reset resets the backoff state (no-op for stateless implementation).
type HTTPStatusClassifier ¶
type HTTPStatusClassifier struct{}
HTTPStatusClassifier classifies errors based on HTTP status codes.
func (*HTTPStatusClassifier) ClassifyStatus ¶
func (c *HTTPStatusClassifier) ClassifyStatus(status int, message string) ErrorInfo
ClassifyStatus returns ErrorInfo based on HTTP status code.
type LinearBackoff ¶
type LinearBackoff struct {
// Initial is the delay for the first retry (default: 1s).
Initial time.Duration
// Increment is added for each subsequent attempt (default: 1s).
Increment time.Duration
// Max is the maximum delay (default: 30s).
Max time.Duration
}
LinearBackoff increases delay linearly with each attempt.
The delay for attempt n is: min(Initial + Increment*(n-1), Max)
func (*LinearBackoff) NextDelay ¶
func (b *LinearBackoff) NextDelay(attempt int) time.Duration
NextDelay returns the delay before the next retry attempt.
func (*LinearBackoff) Reset ¶
func (b *LinearBackoff) Reset()
Reset resets the backoff state (no-op for stateless implementation).
type NoBackoff ¶
type NoBackoff struct{}
NoBackoff returns zero delay (immediate retry). Use with caution; typically only for testing.
type ProviderError ¶
type ProviderError struct {
// Provider is the name of the provider (e.g., "elevenlabs").
Provider string
// Op is the operation that failed (e.g., "Synthesize").
Op string
// Err is the underlying error.
Err error
// Info contains AX metadata about the error.
Info ErrorInfo
}
ProviderError wraps provider errors with AX metadata. It implements the error interface and supports error unwrapping.
func IsProviderError ¶
func IsProviderError(err error) (*ProviderError, bool)
IsProviderError checks if err is a ProviderError and returns it.
func NewProviderError ¶
func NewProviderError(provider, op string, err error, info ErrorInfo) *ProviderError
NewProviderError creates a new ProviderError.
func (*ProviderError) Error ¶
func (e *ProviderError) Error() string
Error returns the error message.
func (*ProviderError) GetCategory ¶
func (e *ProviderError) GetCategory() ErrorCategory
GetCategory returns the error category.
func (*ProviderError) GetCode ¶
func (e *ProviderError) GetCode() string
GetCode returns the error code.
func (*ProviderError) GetRetryAfter ¶
func (e *ProviderError) GetRetryAfter() time.Duration
GetRetryAfter returns the suggested retry delay.
func (*ProviderError) GetSuggestion ¶
func (e *ProviderError) GetSuggestion() string
GetSuggestion returns the recovery suggestion.
func (*ProviderError) Is ¶
func (e *ProviderError) Is(target error) bool
Is reports whether any error in the chain matches target.
func (*ProviderError) IsRetryable ¶
func (e *ProviderError) IsRetryable() bool
IsRetryable returns true if the error can be retried.
func (*ProviderError) Unwrap ¶
func (e *ProviderError) Unwrap() error
Unwrap returns the underlying error.
type RetryConfig ¶
type RetryConfig struct {
// MaxAttempts is the maximum number of attempts (including initial).
// Default: 3 (1 initial + 2 retries).
MaxAttempts int
// Backoff is the strategy for computing delays between retries.
// Default: ExponentialBackoff with sensible defaults.
Backoff BackoffStrategy
// Classifier categorizes errors to determine retryability.
// Default: DefaultClassifier.
Classifier ErrorClassifier
// RetryIf is an optional predicate for custom retry decisions.
// If set, overrides the classifier's retryability decision.
// Return true to retry, false to stop.
RetryIf func(err error) bool
// OnRetry is called before each retry attempt.
// Can be used for logging or metrics.
OnRetry func(attempt int, err error, delay time.Duration)
}
RetryConfig controls retry behavior.
func DefaultRetryConfig ¶
func DefaultRetryConfig() RetryConfig
DefaultRetryConfig returns a RetryConfig with sensible defaults.
func (*RetryConfig) Validate ¶
func (c *RetryConfig) Validate()
Validate ensures the config has valid values, applying defaults where needed.
type RetryError ¶
type RetryError struct {
// Attempts is the number of attempts made.
Attempts int
// Err is the last error encountered.
Err error
}
RetryError wraps the last error with retry context.
func (*RetryError) Unwrap ¶
func (e *RetryError) Unwrap() error
Unwrap returns the underlying error.