httpclient

package
v0.6.17 Latest Latest
Warning

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

Go to latest
Published: Feb 25, 2025 License: Apache-2.0 Imports: 8 Imported by: 0

README

ajan/httpclient

A resilient HTTP client that is 100% compatible with the standard net/http interfaces while providing additional features for improved reliability and fault tolerance.

Features

  • Drop-in replacement for net/http.Client
  • Circuit breaker pattern implementation
  • Exponential backoff retry mechanism with jitter
  • Context-aware request handling
  • Configurable failure thresholds and timeouts
  • Support for HTTP request body retries (when GetBody is implemented)

Usage

Basic Usage
// Create a client with default settings
client := httpclient.DefaultClient()

// Make requests as you would with http.Client
resp, err := client.Get("https://api.example.com")
if err != nil {
  // Handle error
}
defer resp.Body.Close()
Custom Configuration
// Configure circuit breaker
cb := httpclient.NewCircuitBreaker(
  5,              // Failure threshold
  10*time.Second, // Reset timeout
  2,              // Half-open success needed
)

// Configure retry strategy
rs := httpclient.NewRetryStrategy(
  3,                    // Max attempts
  100*time.Millisecond, // Initial interval
  10*time.Second,       // Max interval
  2.0,                  // Multiplier
  0.1,                  // Random factor
)

// Create client with custom settings
client := httpclient.NewClient(cb, rs)
Context Support
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://api.example.com", nil)
if err != nil {
  // Handle error
}

resp, err := client.Do(req)
if err != nil {
  // Handle error
}
defer resp.Body.Close()

Circuit Breaker States

The circuit breaker has three states:

  1. Closed (default): Requests flow normally
  2. Open: Requests are immediately rejected
  3. Half-Open: Limited requests are allowed to test the service

Retry Strategy

The retry mechanism implements exponential backoff with optional jitter:

  • Initial retry interval grows exponentially with each attempt
  • Random jitter helps prevent thundering herd problems
  • Maximum interval caps the exponential growth
  • Configurable maximum number of attempts

Error Handling

The client provides specific error types for different failure scenarios:

  • ErrCircuitOpen: When the circuit breaker is open
  • ErrMaxRetries: When maximum retry attempts are exceeded
  • ErrRequestBodyNotRetriable: When request body cannot be retried

Best Practices

  1. Always use context for request timeouts
  2. Close response bodies
  3. Implement GetBody for POST/PUT requests that need retry support
  4. Configure circuit breaker thresholds based on your service's characteristics
  5. Use appropriate retry settings to avoid overwhelming downstream services

Thread Safety

The client is safe for concurrent use by multiple goroutines.

Documentation

Index

Constants

View Source
const (
	DefaultMaxAttempts     = 3
	DefaultInitialInterval = 100 * time.Millisecond
	DefaultMaxInterval     = 10 * time.Second
	DefaultMultiplier      = 2.0
	DefaultRandomFactor    = 0.1
)
View Source
const (
	DefaultFailureThreshold     = 5
	DefaultResetTimeout         = 10 * time.Second
	DefaultHalfOpenSuccess      = 2
	DefaultServerErrorThreshold = 500
)

Variables

View Source
var (
	// ErrCircuitOpen is returned when the circuit breaker is open.
	ErrCircuitOpen = errors.New("circuit breaker is open")
	// ErrMaxRetries is returned when max retries are exceeded.
	ErrMaxRetries = errors.New("max retries exceeded")
	// ErrRequestBodyNotRetriable is returned when request body cannot be retried.
	ErrRequestBodyNotRetriable = errors.New("request body cannot be retried, implement GetBody to enable retries")
)

Functions

This section is empty.

Types

type CircuitBreaker

type CircuitBreaker struct {
	Config CircuitBreakerConfig
	// contains filtered or unexported fields
}

func NewCircuitBreaker

func NewCircuitBreaker(config CircuitBreakerConfig) *CircuitBreaker

func (*CircuitBreaker) IsAllowed

func (cb *CircuitBreaker) IsAllowed() bool

func (*CircuitBreaker) OnFailure

func (cb *CircuitBreaker) OnFailure()

func (*CircuitBreaker) OnSuccess

func (cb *CircuitBreaker) OnSuccess()

func (*CircuitBreaker) State

func (cb *CircuitBreaker) State() CircuitState

type CircuitBreakerConfig

type CircuitBreakerConfig struct {
	Enabled               bool          `conf:"ENABLED"                  default:"true"`
	FailureThreshold      uint          `conf:"FAILURE_THRESHOLD"        default:"5"`
	ResetTimeout          time.Duration `conf:"RESET_TIMEOUT"            default:"10s"`
	HalfOpenSuccessNeeded uint          `conf:"HALF_OPEN_SUCCESS_NEEDED" default:"2"`
	ServerErrorThreshold  int           `conf:"SERVER_ERROR_THRESHOLD"   default:"500"`
}

type CircuitState

type CircuitState int
const (
	StateClosed CircuitState = iota
	StateHalfOpen
	StateOpen
)

type Client

type Client struct {
	*http.Client
	// contains filtered or unexported fields
}

Client is a drop-in replacement for http.Client with built-in circuit breaker and retry mechanisms.

func DefaultClient

func DefaultClient() *Client

DefaultClient creates a new HTTP client with default circuit breaker and retry settings.

func NewClient

func NewClient(cb *CircuitBreaker, rs *RetryStrategy) *Client

NewClient creates a new HTTP client with the specified circuit breaker and retry strategy.

func (*Client) CircuitBreaker

func (c *Client) CircuitBreaker() *CircuitBreaker

CircuitBreaker returns the underlying circuit breaker.

func (*Client) RetryStrategy

func (c *Client) RetryStrategy() *RetryStrategy

RetryStrategy returns the underlying retry strategy.

type Config

type Config struct {
	CircuitBreaker CircuitBreakerConfig `conf:"CIRCUIT_BREAKER"`
	Retry          RetryConfig          `conf:"RETRY"`
}

type ResilientTransport

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

func NewResilientTransport

func NewResilientTransport(transport http.RoundTripper, cb *CircuitBreaker, rs *RetryStrategy) *ResilientTransport

func (*ResilientTransport) CancelRequest

func (t *ResilientTransport) CancelRequest(req *http.Request)

CancelRequest implements the optional CancelRequest method for http.RoundTripper.

func (*ResilientTransport) RoundTrip

func (t *ResilientTransport) RoundTrip(req *http.Request) (*http.Response, error)

type RetryConfig

type RetryConfig struct {
	Enabled         bool          `conf:"ENABLED"          default:"true"`
	MaxAttempts     uint          `conf:"MAX_ATTEMPTS"     default:"3"`
	InitialInterval time.Duration `conf:"INITIAL_INTERVAL" default:"100ms"`
	MaxInterval     time.Duration `conf:"MAX_INTERVAL"     default:"10s"`
	Multiplier      float64       `conf:"MULTIPLIER"       default:"2"`
	RandomFactor    float64       `conf:"RANDOM_FACTOR"    default:"0.1"`
}

type RetryStrategy

type RetryStrategy struct {
	Config RetryConfig
}

func DefaultRetryStrategy

func DefaultRetryStrategy() *RetryStrategy

func NewRetryStrategy

func NewRetryStrategy(config RetryConfig) *RetryStrategy

NewRetryStrategy creates a new retry strategy with the specified parameters.

func (*RetryStrategy) NextBackoff

func (r *RetryStrategy) NextBackoff(attempt uint) time.Duration

Jump to

Keyboard shortcuts

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