retryfs

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Dec 12, 2025 License: MIT Imports: 16 Imported by: 0

README

retryfs

Go Reference Go Report Card CI License

Automatic retry with exponential backoff for network filesystems in the AbsFS ecosystem.

Overview

retryfs is a filesystem wrapper that provides automatic retry logic with configurable backoff strategies for unreliable or network-based filesystems. It implements the absfs.FileSystem interface and transparently handles transient failures, making network filesystems more resilient without requiring application-level retry logic.

Key features:

  • Exponential backoff with configurable parameters
  • Jitter to prevent thundering herd problems
  • Circuit breaker pattern to fail fast when backend is down
  • Error classification to determine which errors are retryable
  • Configurable retry policies per operation type
  • Metrics and observability for monitoring retry behavior
  • Idempotency awareness to safely retry operations

Retry Strategies

Exponential Backoff

The default retry strategy uses exponential backoff with jitter:

delay = min(maxDelay, baseDelay * 2^attempt) + random(-jitter, +jitter)
  • Base delay: Initial delay before first retry (default: 100ms)
  • Max delay: Maximum delay between retries (default: 30s)
  • Max attempts: Maximum number of retry attempts (default: 5)
  • Jitter: Random variance added to delay (default: ±25%)
Circuit Breaker

Prevents cascading failures when the underlying filesystem is consistently unavailable:

  • Failure threshold: Number of consecutive failures to open circuit (default: 5)
  • Success threshold: Number of consecutive successes to close circuit (default: 2)
  • Timeout: How long to wait in open state before trying again (default: 60s)
  • Half-open: Test with single request before fully closing circuit

States:

  • Closed: Normal operation, requests pass through
  • Open: Too many failures, requests fail immediately
  • Half-Open: Testing if backend has recovered
Adaptive Backoff

Learn from success/failure patterns to optimize retry timing:

  • Track success rates per operation type
  • Adjust backoff parameters based on observed latency
  • Detect patterns in transient vs permanent failures

Implementation Phases

Phase 1: Core Retry Logic

Foundation for retry behavior:

  • Implement retry wrapper for absfs.FileSystem interface
  • Exponential backoff with jitter algorithm
  • Configurable retry policies (per-operation and global)
  • Error classification system (retryable vs non-retryable)
  • Basic metrics collection (attempts, successes, failures)
Phase 2: Error Classification

Intelligent error handling:

  • Categorize errors by type (network, timeout, permission, not found, etc.)
  • Default retry policies for common error classes
  • Configurable error classifiers for custom error types
  • Idempotency detection for write operations
  • Support for wrapped/nested errors
Phase 3: Circuit Breaker

Fail-fast behavior for degraded backends:

  • Circuit breaker state machine
  • Per-operation circuit breakers (optional)
  • Health check probes during half-open state
  • Configurable thresholds and timeouts
  • Circuit breaker metrics and events
Phase 4: Advanced Features

Enhanced reliability and observability:

  • Adaptive backoff based on success patterns
  • Request hedging (parallel retries after timeout)
  • Priority queuing for retry attempts
  • Deadline propagation and context support
  • Structured logging and tracing integration
  • Prometheus metrics exporter
Phase 5: Testing and Documentation

Ensure reliability and ease of use:

  • Comprehensive unit tests with mocked failures
  • Integration tests with real network filesystems
  • Chaos engineering tests (random failures)
  • Performance benchmarks
  • Usage examples and guides
  • Best practices documentation

API Design

Basic Usage
import (
    "github.com/absfs/retryfs"
    "github.com/absfs/s3fs"
)

// Wrap an unreliable filesystem with default retry policy
underlying := s3fs.New(bucket)
fs := retryfs.New(underlying)

// Use normally - retries are automatic
file, err := fs.Open("/data/file.txt")
Custom Retry Policy
policy := &retryfs.Policy{
    MaxAttempts:  3,
    BaseDelay:    50 * time.Millisecond,
    MaxDelay:     5 * time.Second,
    Jitter:       0.1, // ±10%
    Multiplier:   2.0, // Exponential factor
}

fs := retryfs.New(underlying, retryfs.WithPolicy(policy))
Per-Operation Policies
config := &retryfs.Config{
    DefaultPolicy: retryfs.DefaultPolicy,
    OperationPolicies: map[retryfs.Operation]*retryfs.Policy{
        retryfs.OpRead: {
            MaxAttempts: 5,
            BaseDelay:   100 * time.Millisecond,
        },
        retryfs.OpWrite: {
            MaxAttempts: 3,  // Fewer retries for writes
            BaseDelay:   200 * time.Millisecond,
        },
        retryfs.OpStat: {
            MaxAttempts: 10, // More retries for cheap operations
            BaseDelay:   50 * time.Millisecond,
        },
    },
}

fs := retryfs.New(underlying, retryfs.WithConfig(config))
Circuit Breaker Configuration
cb := &retryfs.CircuitBreaker{
    FailureThreshold: 10,
    SuccessThreshold: 2,
    Timeout:          60 * time.Second,
    OnStateChange: func(from, to retryfs.State) {
        log.Printf("Circuit breaker: %s -> %s", from, to)
    },
}

fs := retryfs.New(underlying, retryfs.WithCircuitBreaker(cb))
Custom Error Classification
classifier := func(err error) retryfs.ErrorClass {
    if errors.Is(err, s3.ErrThrottled) {
        return retryfs.ErrorRetryable
    }
    if errors.Is(err, s3.ErrNotFound) {
        return retryfs.ErrorPermanent
    }
    if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
        return retryfs.ErrorRetryable
    }
    return retryfs.ErrorUnknown
}

fs := retryfs.New(underlying, retryfs.WithErrorClassifier(classifier))
Context and Deadlines
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

// Retries will respect context deadline
file, err := fs.OpenContext(ctx, "/data/file.txt")

Usage Examples

S3 Filesystem with Retries
import (
    "github.com/absfs/retryfs"
    "github.com/absfs/s3fs"
)

// S3 can have transient failures due to rate limiting
s3 := s3fs.New("my-bucket", s3fs.WithRegion("us-west-2"))

// Wrap with retry logic
policy := &retryfs.Policy{
    MaxAttempts: 5,
    BaseDelay:   200 * time.Millisecond,
    MaxDelay:    10 * time.Second,
}

fs := retryfs.New(s3,
    retryfs.WithPolicy(policy),
    retryfs.WithCircuitBreaker(&retryfs.CircuitBreaker{
        FailureThreshold: 5,
        Timeout:          30 * time.Second,
    }),
)

// All operations automatically retry on transient failures
data, err := fs.ReadFile("/config.json")
WebDAV Filesystem with Retries
import (
    "github.com/absfs/retryfs"
    "github.com/absfs/webdavfs"
)

// WebDAV over flaky network connection
webdav := webdavfs.New("https://dav.example.com/files")

// Configure aggressive retries for network issues
fs := retryfs.New(webdav,
    retryfs.WithPolicy(&retryfs.Policy{
        MaxAttempts: 10,
        BaseDelay:   100 * time.Millisecond,
        MaxDelay:    30 * time.Second,
        Jitter:      0.25,
    }),
)

// Reliable file operations despite network issues
err := fs.MkdirAll("/backup/2024", 0755)
Layered Reliability
import (
    "github.com/absfs/retryfs"
    "github.com/absfs/cachefs"
    "github.com/absfs/s3fs"
)

// Combine caching and retries for maximum reliability
s3 := s3fs.New("my-bucket")
cached := cachefs.New(s3)
reliable := retryfs.New(cached)

// Cache reduces load, retries handle transient failures
fs := reliable

Idempotency Considerations

Retry logic must be careful with non-idempotent operations to avoid unintended side effects.

Idempotent Operations

Safe to retry without additional logic:

  • Read operations: Open, ReadFile, Stat, Lstat, Readlink
  • Directory listings: ReadDir, Glob
  • Idempotent writes: Create (if it fails, file wasn't created), Remove (if it fails, file wasn't removed)
Non-Idempotent Operations

Require careful handling:

  • Append operations: Retrying may append data multiple times
  • Rename/Move: Retrying after success but before confirmation may fail
  • Partial writes: Write failures may leave partial data
Strategies
  1. Track request IDs: Use unique IDs to detect duplicate requests
  2. Check state before retry: Verify operation didn't succeed before retrying
  3. Conservative policies: Use fewer retries for risky operations
  4. Idempotency tokens: Support backend-specific deduplication

Example implementation:

// Before retrying a write, check if it already succeeded
func (r *RetryFS) retryWrite(path string, data []byte) error {
    var lastErr error
    for attempt := 0; attempt < r.policy.MaxAttempts; attempt++ {
        if attempt > 0 {
            // Check if previous attempt actually succeeded
            if info, err := r.fs.Stat(path); err == nil {
                if info.Size() == int64(len(data)) {
                    // Write probably succeeded on last attempt
                    return nil
                }
            }
            time.Sleep(r.backoff(attempt))
        }

        if err := r.fs.WriteFile(path, data, 0644); err != nil {
            lastErr = err
            continue
        }
        return nil
    }
    return lastErr
}

Error Classification

Not all errors should trigger retries. retryfs classifies errors into categories:

Retryable Errors

Transient failures that may succeed on retry:

  • Network errors: Connection refused, timeout, temporary DNS failure
  • Rate limiting: HTTP 429, S3 throttling
  • Temporary unavailability: HTTP 503, backend overload
  • Concurrent access: Optimistic locking failures
  • Resource exhaustion: Temporary out of memory, file descriptors
Non-Retryable Errors

Permanent failures that won't change on retry:

  • Not found: File or directory doesn't exist (HTTP 404)
  • Permission denied: Authentication or authorization failure (HTTP 403)
  • Invalid input: Malformed path, invalid arguments (HTTP 400)
  • Not supported: Operation not implemented
  • Quota exceeded: Storage limit reached
Unknown Errors

Errors that don't clearly fit a category:

  • Default behavior: Retry with conservative policy
  • Can be configured to treat as retryable or permanent
  • Logged for manual classification
Custom Classification
// Define custom error types
var (
    ErrQuotaExceeded = errors.New("storage quota exceeded")
    ErrRateLimited   = errors.New("rate limited")
)

// Configure classifier
classifier := func(err error) retryfs.ErrorClass {
    switch {
    case errors.Is(err, ErrQuotaExceeded):
        return retryfs.ErrorPermanent
    case errors.Is(err, ErrRateLimited):
        return retryfs.ErrorRetryable
    default:
        return retryfs.ErrorUnknown
    }
}

fs := retryfs.New(underlying, retryfs.WithErrorClassifier(classifier))

Performance Impact

Retry logic adds overhead that should be understood and monitored:

Latency Impact
  • Success case: Minimal overhead (function call + error check)
  • Retry case: Additional latency = sum of backoff delays
  • Circuit open: Near-zero overhead (fail immediately)

Example: 3 retries with 100ms, 200ms, 400ms delays = 700ms added latency

Throughput Impact
  • No retries: No impact on throughput
  • With retries: Reduced effective throughput during failures
  • Circuit breaker: Prevents wasted attempts on dead backend
Resource Impact
  • Memory: Minimal per-filesystem instance (config + circuit state)
  • Goroutines: No additional goroutines in basic implementation
  • CPU: Negligible for backoff calculations
Optimization Strategies
  1. Tune retry parameters: Balance reliability vs latency
  2. Per-operation policies: Aggressive for cheap ops, conservative for expensive
  3. Circuit breaker: Prevent retry storms
  4. Metrics: Monitor retry rates to detect issues
  5. Adaptive backoff: Learn optimal parameters from real traffic
Benchmarks
BenchmarkOpen_NoRetry          100000    12500 ns/op
BenchmarkOpen_WithRetryWrapper 100000    12650 ns/op  (+1.2%)
BenchmarkOpen_WithRetry_1Fail  10000    125000 ns/op  (1 retry, 100ms delay)
BenchmarkOpen_WithRetry_3Fail   1000   1250000 ns/op  (3 retries, 700ms total)

Monitoring and Observability

Track retry behavior to understand system reliability:

Metrics
  • retryfs_attempts_total{operation, result}: Total retry attempts
  • retryfs_retries_total{operation}: Number of retries executed
  • retryfs_circuit_state{name}: Current circuit breaker state (0=closed, 1=open, 2=half-open)
  • retryfs_errors_total{operation, class}: Errors by classification
  • retryfs_operation_duration_seconds{operation}: Operation latency histogram
Logging
logger := log.New(os.Stdout, "retryfs: ", log.LstdFlags)
fs := retryfs.New(underlying,
    retryfs.WithLogger(logger),
    retryfs.WithVerbosity(retryfs.LogRetries), // Log each retry attempt
)
Events
events := make(chan retryfs.Event, 100)
fs := retryfs.New(underlying, retryfs.WithEvents(events))

go func() {
    for event := range events {
        switch e := event.(type) {
        case *retryfs.RetryEvent:
            log.Printf("Retry %d/%d for %s: %v",
                e.Attempt, e.MaxAttempts, e.Operation, e.Error)
        case *retryfs.CircuitEvent:
            log.Printf("Circuit %s -> %s", e.From, e.To)
        }
    }
}()

Documentation

  • Best Practices Guide - Production deployment guidelines, configuration recommendations, and common pitfalls
  • Integration Testing Guide - Comprehensive patterns and examples for integration testing with RetryFS
  • Examples - Working examples demonstrating various features
  • API Reference - See inline documentation and godoc

Observability

RetryFS provides comprehensive observability features:

Prometheus Metrics
collector := retryfs.NewPrometheusCollector(fs, "myapp", "storage")
prometheus.DefaultRegisterer.MustRegister(collector)

Available Metrics:

  • retryfs_attempts_total{operation} - Total operation attempts
  • retryfs_retries_total{operation} - Retry count per operation
  • retryfs_successes_total{operation} - Successful operations
  • retryfs_failures_total{operation} - Failed operations (after all retries)
  • retryfs_errors_total{class} - Errors by classification
  • retryfs_circuit_state - Circuit breaker state (0=closed, 1=open, 2=half-open)
  • retryfs_circuit_consecutive_errors - Consecutive error count
  • retryfs_circuit_consecutive_successes - Consecutive success count
Per-Operation Circuit Breakers

For fine-grained control, use per-operation circuit breakers:

pocb := retryfs.NewPerOperationCircuitBreaker(&retryfs.CircuitBreakerConfig{
    FailureThreshold: 5,
    SuccessThreshold: 2,
    Timeout:          30 * time.Second,
    OnStateChange: func(op retryfs.Operation, from, to retryfs.State) {
        log.Printf("[%s] Circuit: %s -> %s", op, from, to)
    },
})

fs := retryfs.New(backend, retryfs.WithPerOperationCircuitBreaker(pocb))

This allows reads to continue working even if writes are failing.

Contributing

Contributions are welcome! Please see the AbsFS contribution guidelines.

License

MIT License - see LICENSE file for details.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var DefaultPolicy = &Policy{
	MaxAttempts: 5,
	BaseDelay:   100 * time.Millisecond,
	MaxDelay:    30 * time.Second,
	Jitter:      0.25,
	Multiplier:  2.0,
}

DefaultPolicy provides sensible defaults for retry behavior

View Source
var (
	// ErrCircuitOpen is returned when the circuit breaker is open
	ErrCircuitOpen = errors.New("circuit breaker is open")
)

Functions

func IsPermanent

func IsPermanent(err error) bool

IsPermanent is a helper function to determine if an error is permanent using the default classifier

func IsRetryable

func IsRetryable(err error) bool

IsRetryable is a helper function to determine if an error is retryable using the default classifier

func New

func New(fs absfs.FileSystem, options ...Option) absfs.FileSystem

New creates a new RetryFS wrapping the given filesystem

Types

type CircuitBreaker

type CircuitBreaker struct {
	// FailureThreshold is the number of consecutive failures to open the circuit
	FailureThreshold int
	// SuccessThreshold is the number of consecutive successes to close the circuit from half-open
	SuccessThreshold int
	// Timeout is how long to wait in open state before trying half-open
	Timeout time.Duration
	// OnStateChange is called when the circuit breaker changes state
	OnStateChange func(from, to State)
	// contains filtered or unexported fields
}

CircuitBreaker implements the circuit breaker pattern

func NewCircuitBreaker

func NewCircuitBreaker() *CircuitBreaker

NewCircuitBreaker creates a new CircuitBreaker with default settings

func (*CircuitBreaker) Call

func (cb *CircuitBreaker) Call(fn func() error) error

Call executes the given function with circuit breaker protection

func (*CircuitBreaker) GetState

func (cb *CircuitBreaker) GetState() State

GetState returns the current state of the circuit breaker

func (*CircuitBreaker) GetStats

func (cb *CircuitBreaker) GetStats() CircuitBreakerStats

GetStats returns statistics about the circuit breaker

func (*CircuitBreaker) Reset

func (cb *CircuitBreaker) Reset()

Reset resets the circuit breaker to closed state

type CircuitBreakerConfig

type CircuitBreakerConfig struct {
	FailureThreshold int
	SuccessThreshold int
	Timeout          time.Duration
	OnStateChange    func(op Operation, from, to State)
}

CircuitBreakerConfig holds configuration for creating new circuit breakers

type CircuitBreakerStats

type CircuitBreakerStats struct {
	State              State
	ConsecutiveErrors  int
	ConsecutiveSuccess int
	LastFailureTime    time.Time
}

CircuitBreakerStats contains statistics about a circuit breaker

type Config

type Config struct {
	// DefaultPolicy is the policy used when no operation-specific policy exists
	DefaultPolicy *Policy
	// OperationPolicies maps operations to their specific retry policies
	OperationPolicies map[Operation]*Policy
	// ErrorClassifier classifies errors as retryable or permanent
	ErrorClassifier ErrorClassifier
	// OnRetry is called before each retry attempt
	OnRetry func(op Operation, attempt int, err error)
}

Config holds the configuration for RetryFS

func DefaultConfig

func DefaultConfig() *Config

DefaultConfig returns a new Config with sensible defaults

func (*Config) GetPolicy

func (c *Config) GetPolicy(op Operation) *Policy

GetPolicy returns the policy for a given operation

type ErrorClass

type ErrorClass int

ErrorClass represents the classification of an error

const (
	// ErrorUnknown means we can't determine if the error is retryable
	ErrorUnknown ErrorClass = iota
	// ErrorRetryable means the error is transient and may succeed on retry
	ErrorRetryable
	// ErrorPermanent means the error is permanent and won't change on retry
	ErrorPermanent
)

func (ErrorClass) String

func (ec ErrorClass) String() string

String returns a string representation of the ErrorClass

type ErrorClassifier

type ErrorClassifier func(err error) ErrorClass

ErrorClassifier is a function that classifies an error

type Logger

type Logger interface {
	// Debug logs a debug message with structured fields
	Debug(msg string, keysAndValues ...interface{})
	// Info logs an info message with structured fields
	Info(msg string, keysAndValues ...interface{})
	// Warn logs a warning message with structured fields
	Warn(msg string, keysAndValues ...interface{})
	// Error logs an error message with structured fields
	Error(msg string, keysAndValues ...interface{})
}

Logger is the interface for structured logging

func NewSlogLogger

func NewSlogLogger(logger *slog.Logger) Logger

NewSlogLogger creates a Logger from a slog.Logger

type Metrics

type Metrics struct {
	// TotalAttempts is the total number of attempts across all operations
	TotalAttempts int64
	// TotalRetries is the total number of retries (attempts - initial tries)
	TotalRetries int64
	// TotalSuccesses is the total number of successful operations
	TotalSuccesses int64
	// TotalFailures is the total number of failed operations (after all retries)
	TotalFailures int64
	// ErrorsByClass tracks errors by their classification
	ErrorsByClass map[ErrorClass]int64
	// OperationMetrics tracks metrics per operation type
	OperationMetrics map[Operation]*OperationMetrics
}

Metrics holds statistics about retry behavior

func NewMetrics

func NewMetrics() *Metrics

NewMetrics creates a new Metrics instance

func (*Metrics) RecordAttempt

func (m *Metrics) RecordAttempt(op Operation, isRetry bool)

RecordAttempt records an attempt for an operation

func (*Metrics) RecordFailure

func (m *Metrics) RecordFailure(op Operation, errClass ErrorClass)

RecordFailure records a failed operation

func (*Metrics) RecordSuccess

func (m *Metrics) RecordSuccess(op Operation)

RecordSuccess records a successful operation

type NoopLogger

type NoopLogger struct{}

NoopLogger is a logger that does nothing

func (*NoopLogger) Debug

func (n *NoopLogger) Debug(msg string, keysAndValues ...interface{})

func (*NoopLogger) Error

func (n *NoopLogger) Error(msg string, keysAndValues ...interface{})

func (*NoopLogger) Info

func (n *NoopLogger) Info(msg string, keysAndValues ...interface{})

func (*NoopLogger) Warn

func (n *NoopLogger) Warn(msg string, keysAndValues ...interface{})

type Operation

type Operation string

Operation represents a filesystem operation type

const (
	OpOpen      Operation = "open"
	OpCreate    Operation = "create"
	OpOpenFile  Operation = "openfile"
	OpStat      Operation = "stat"
	OpLstat     Operation = "lstat"
	OpMkdir     Operation = "mkdir"
	OpMkdirAll  Operation = "mkdirall"
	OpRemove    Operation = "remove"
	OpRemoveAll Operation = "removeall"
	OpRename    Operation = "rename"
	OpChmod     Operation = "chmod"
	OpChown     Operation = "chown"
	OpLchown    Operation = "lchown"
	OpChtimes   Operation = "chtimes"
	OpChdir     Operation = "chdir"
	OpGetwd     Operation = "getwd"
	OpTruncate  Operation = "truncate"
	OpSymlink   Operation = "symlink"
	OpReadlink  Operation = "readlink"
	OpReadDir   Operation = "readdir"
	OpReadFile  Operation = "readfile"
	OpSub       Operation = "sub"
)

type OperationMetrics

type OperationMetrics struct {
	Attempts  int64
	Retries   int64
	Successes int64
	Failures  int64
}

OperationMetrics holds metrics for a specific operation type

type Option

type Option func(*RetryFS)

Option is a functional option for configuring RetryFS

func WithCircuitBreaker

func WithCircuitBreaker(cb *CircuitBreaker) Option

WithCircuitBreaker enables circuit breaker protection

func WithConfig

func WithConfig(config *Config) Option

WithConfig sets the entire configuration

func WithErrorClassifier

func WithErrorClassifier(classifier ErrorClassifier) Option

WithErrorClassifier sets a custom error classifier

func WithLogger

func WithLogger(logger Logger) Option

WithLogger sets a structured logger

func WithOnRetry

func WithOnRetry(onRetry func(op Operation, attempt int, err error)) Option

WithOnRetry sets a callback for retry events

func WithPerOperationCircuitBreaker

func WithPerOperationCircuitBreaker(pocb *PerOperationCircuitBreaker) Option

WithPerOperationCircuitBreaker enables per-operation circuit breaker protection

func WithPolicy

func WithPolicy(policy *Policy) Option

WithPolicy sets the default retry policy

type PerOperationCircuitBreaker

type PerOperationCircuitBreaker struct {
	// contains filtered or unexported fields
}

PerOperationCircuitBreaker manages circuit breakers for individual operations

func NewPerOperationCircuitBreaker

func NewPerOperationCircuitBreaker(config *CircuitBreakerConfig) *PerOperationCircuitBreaker

NewPerOperationCircuitBreaker creates a new per-operation circuit breaker manager

func (*PerOperationCircuitBreaker) Call

func (pocb *PerOperationCircuitBreaker) Call(op Operation, fn func() error) error

Call executes a function with the circuit breaker for the given operation

func (*PerOperationCircuitBreaker) GetAllStates

func (pocb *PerOperationCircuitBreaker) GetAllStates() map[Operation]State

GetAllStates returns the state of all circuit breakers

func (*PerOperationCircuitBreaker) GetAllStats

GetAllStats returns statistics for all circuit breakers

func (*PerOperationCircuitBreaker) GetCircuitBreaker

func (pocb *PerOperationCircuitBreaker) GetCircuitBreaker(op Operation) *CircuitBreaker

GetCircuitBreaker returns the circuit breaker for a specific operation Creates one if it doesn't exist

func (*PerOperationCircuitBreaker) Reset

func (pocb *PerOperationCircuitBreaker) Reset()

Reset resets all circuit breakers

func (*PerOperationCircuitBreaker) ResetOperation

func (pocb *PerOperationCircuitBreaker) ResetOperation(op Operation)

ResetOperation resets the circuit breaker for a specific operation

type Policy

type Policy struct {
	// MaxAttempts is the maximum number of attempts (including the first try)
	MaxAttempts int
	// BaseDelay is the initial delay before the first retry
	BaseDelay time.Duration
	// MaxDelay is the maximum delay between retries
	MaxDelay time.Duration
	// Jitter is the random variance factor (0.0 to 1.0) added to delay
	// A jitter of 0.25 means ±25% randomness
	Jitter float64
	// Multiplier is the exponential backoff multiplier (usually 2.0)
	Multiplier float64
}

Policy defines the retry behavior

type PrometheusCollector

type PrometheusCollector struct {
	// contains filtered or unexported fields
}

PrometheusCollector collects retryfs metrics for Prometheus

func NewPrometheusCollector

func NewPrometheusCollector(rfs *RetryFS, namespace, subsystem string) *PrometheusCollector

NewPrometheusCollector creates a new Prometheus collector for the given RetryFS

func (*PrometheusCollector) Collect

func (c *PrometheusCollector) Collect(ch chan<- prometheus.Metric)

Collect implements prometheus.Collector

func (*PrometheusCollector) Describe

func (c *PrometheusCollector) Describe(ch chan<- *prometheus.Desc)

Describe implements prometheus.Collector

func (*PrometheusCollector) MustRegister

func (c *PrometheusCollector) MustRegister(registry *prometheus.Registry)

MustRegister registers the collector with the provided Prometheus registry It panics if registration fails

func (*PrometheusCollector) Register

func (c *PrometheusCollector) Register(registry *prometheus.Registry) error

Register registers the collector with the provided Prometheus registry Returns an error if registration fails

type RetryFS

type RetryFS struct {
	// contains filtered or unexported fields
}

RetryFS wraps an absfs.FileSystem with automatic retry logic

func (*RetryFS) Chdir

func (rfs *RetryFS) Chdir(dir string) error

Chdir implements absfs.FileSystem

func (*RetryFS) Chmod

func (rfs *RetryFS) Chmod(name string, mode os.FileMode) error

Chmod implements absfs.FileSystem

func (*RetryFS) ChmodContext

func (rfs *RetryFS) ChmodContext(ctx context.Context, name string, mode os.FileMode) error

ChmodContext changes file mode with context support

func (*RetryFS) Chown

func (rfs *RetryFS) Chown(name string, uid, gid int) error

Chown implements absfs.FileSystem

func (*RetryFS) ChownContext

func (rfs *RetryFS) ChownContext(ctx context.Context, name string, uid, gid int) error

ChownContext changes file owner with context support

func (*RetryFS) Chtimes

func (rfs *RetryFS) Chtimes(name string, atime time.Time, mtime time.Time) error

Chtimes implements absfs.FileSystem

func (*RetryFS) ChtimesContext

func (rfs *RetryFS) ChtimesContext(ctx context.Context, name string, atime, mtime time.Time) error

ChtimesContext changes file times with context support

func (*RetryFS) Create

func (rfs *RetryFS) Create(filename string) (absfs.File, error)

Create implements absfs.FileSystem

func (*RetryFS) CreateContext

func (rfs *RetryFS) CreateContext(ctx context.Context, filename string) (absfs.File, error)

CreateContext creates a file with context support

func (*RetryFS) GetCircuitBreaker

func (rfs *RetryFS) GetCircuitBreaker() *CircuitBreaker

GetCircuitBreaker returns the circuit breaker if configured

func (*RetryFS) GetMetrics

func (rfs *RetryFS) GetMetrics() *Metrics

GetMetrics returns the current metrics

func (*RetryFS) GetPerOperationCircuitBreaker

func (rfs *RetryFS) GetPerOperationCircuitBreaker() *PerOperationCircuitBreaker

GetPerOperationCircuitBreaker returns the per-operation circuit breaker if configured

func (*RetryFS) Getwd

func (rfs *RetryFS) Getwd() (string, error)

Getwd implements absfs.FileSystem

func (*RetryFS) Lchown

func (rfs *RetryFS) Lchown(name string, uid, gid int) error

Lchown implements absfs.SymLinker

func (*RetryFS) LchownContext

func (rfs *RetryFS) LchownContext(ctx context.Context, name string, uid, gid int) error

LchownContext changes file owner without following symlinks with context support

func (*RetryFS) Lstat

func (rfs *RetryFS) Lstat(name string) (os.FileInfo, error)

Lstat implements absfs.SymLinker

func (*RetryFS) LstatContext

func (rfs *RetryFS) LstatContext(ctx context.Context, filename string) (os.FileInfo, error)

LstatContext returns file info without following symlinks with context support

func (*RetryFS) Mkdir

func (rfs *RetryFS) Mkdir(name string, perm os.FileMode) error

Mkdir implements absfs.FileSystem

func (*RetryFS) MkdirAll

func (rfs *RetryFS) MkdirAll(filename string, perm os.FileMode) error

MkdirAll implements absfs.FileSystem

func (*RetryFS) MkdirAllContext

func (rfs *RetryFS) MkdirAllContext(ctx context.Context, filename string, perm os.FileMode) error

MkdirAllContext creates a directory tree with context support

func (*RetryFS) Open

func (rfs *RetryFS) Open(filename string) (absfs.File, error)

Open implements absfs.FileSystem

func (*RetryFS) OpenContext

func (rfs *RetryFS) OpenContext(ctx context.Context, filename string) (absfs.File, error)

OpenContext opens a file with context support

func (*RetryFS) OpenFile

func (rfs *RetryFS) OpenFile(filename string, flag int, perm os.FileMode) (absfs.File, error)

OpenFile implements absfs.FileSystem

func (*RetryFS) OpenFileContext

func (rfs *RetryFS) OpenFileContext(ctx context.Context, filename string, flag int, perm os.FileMode) (absfs.File, error)

OpenFileContext opens a file with flags and permissions with context support

func (*RetryFS) ReadDir

func (rfs *RetryFS) ReadDir(name string) ([]fs.DirEntry, error)

ReadDir implements absfs.FileSystem

func (*RetryFS) ReadFile

func (rfs *RetryFS) ReadFile(name string) ([]byte, error)

ReadFile implements absfs.FileSystem

func (rfs *RetryFS) Readlink(name string) (string, error)

Readlink implements absfs.SymLinker

func (*RetryFS) ReadlinkContext

func (rfs *RetryFS) ReadlinkContext(ctx context.Context, link string) (string, error)

ReadlinkContext reads a symbolic link with context support

func (*RetryFS) Remove

func (rfs *RetryFS) Remove(filename string) error

Remove implements absfs.FileSystem

func (*RetryFS) RemoveAll

func (rfs *RetryFS) RemoveAll(path string) error

RemoveAll implements absfs.FileSystem

func (*RetryFS) RemoveContext

func (rfs *RetryFS) RemoveContext(ctx context.Context, filename string) error

RemoveContext removes a file with context support

func (*RetryFS) Rename

func (rfs *RetryFS) Rename(oldpath, newpath string) error

Rename implements absfs.FileSystem

func (*RetryFS) RenameContext

func (rfs *RetryFS) RenameContext(ctx context.Context, oldpath, newpath string) error

RenameContext renames a file with context support

func (*RetryFS) Stat

func (rfs *RetryFS) Stat(filename string) (os.FileInfo, error)

Stat implements absfs.FileSystem

func (*RetryFS) StatContext

func (rfs *RetryFS) StatContext(ctx context.Context, filename string) (os.FileInfo, error)

StatContext returns file info with context support

func (*RetryFS) Sub

func (rfs *RetryFS) Sub(dir string) (fs.FS, error)

Sub implements absfs.FileSystem

func (rfs *RetryFS) Symlink(oldname, newname string) error

Symlink implements absfs.SymLinker

func (*RetryFS) SymlinkContext

func (rfs *RetryFS) SymlinkContext(ctx context.Context, target, link string) error

SymlinkContext creates a symbolic link with context support

func (*RetryFS) TempDir

func (rfs *RetryFS) TempDir() string

TempDir implements absfs.FileSystem

func (*RetryFS) Truncate

func (rfs *RetryFS) Truncate(name string, size int64) error

Truncate implements absfs.FileSystem

type SlogLogger

type SlogLogger struct {
	// contains filtered or unexported fields
}

SlogLogger wraps slog.Logger to implement our Logger interface

func (*SlogLogger) Debug

func (s *SlogLogger) Debug(msg string, keysAndValues ...interface{})

func (*SlogLogger) Error

func (s *SlogLogger) Error(msg string, keysAndValues ...interface{})

func (*SlogLogger) Info

func (s *SlogLogger) Info(msg string, keysAndValues ...interface{})

func (*SlogLogger) Warn

func (s *SlogLogger) Warn(msg string, keysAndValues ...interface{})

type State

type State int

State represents the circuit breaker state

const (
	// StateClosed means the circuit is closed (normal operation)
	StateClosed State = iota
	// StateOpen means the circuit is open (failing fast)
	StateOpen
	// StateHalfOpen means the circuit is testing if the backend has recovered
	StateHalfOpen
)

func (State) String

func (s State) String() string

String returns a string representation of the State

Jump to

Keyboard shortcuts

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