Clients Package

Clients Package

The clients package provides utility features for building robust and resilient client implementations in Go. It includes essential patterns for creating fault-tolerant applications that can gracefully handle communication failures with external services.

Features

  • Retry Handling: Configurable retry logic to handle transient errors
  • Circuit Breaker Pattern: Prevent cascading failures by stopping requests to failing services
  • Authentication Support: Common authentication mechanisms for client applications
  • Extensible Client Options: Flexible configuration for different client types

Core Components

RetryHandler

The RetryHandler allows you to configure retry logic for your client operations. This is particularly useful for handling transient errors and ensuring that your client can recover from temporary failures.

Configuration Parameters

  • MaxRetries: Maximum number of retry attempts
  • Wait: Time to wait between retry attempts (in milliseconds)

CircuitBreaker

The CircuitBreaker pattern helps prevent cascading failures by stopping requests to a failing service. It transitions between different states based on the success or failure of requests:

  • Closed: Normal operation, requests flow through
  • Open: Requests are blocked to prevent further failures
  • Half-Open: Limited requests allowed to test if the service has recovered

Configuration Parameters

  • FailureThreshold: Number of consecutive failures required to open the circuit
  • SuccessThreshold: Number of consecutive successes required to close the circuit
  • MaxHalfOpen: Maximum number of requests allowed in the half-open state
  • Timeout: Timeout duration (in seconds) for the circuit to transition from open to half-open state

Usage Examples

RetryHandler Example

package main

import (
    "fmt"
    "time"
    "oss.nandlabs.io/golly/clients"
)

func main() {
    retryInfo := clients.RetryInfo{
        MaxRetries: 3,
        Wait:       1000, // Wait time in milliseconds
    }

    for i := 0; i < retryInfo.MaxRetries; i++ {
        err := performOperation()
        if err == nil {
            fmt.Println("Operation succeeded")
            break
        }
        fmt.Printf("Operation failed: %v. Retrying...\n", err)
        time.Sleep(time.Duration(retryInfo.Wait) * time.Millisecond)
    }
}

func performOperation() error {
    // Simulate an operation that may fail
    return fmt.Errorf("simulated error")
}

CircuitBreaker Example

package main

import (
    "fmt"
    "oss.nandlabs.io/golly/clients"
)

func main() {
    breakerInfo := &clients.BreakerInfo{
        FailureThreshold: 3,
        SuccessThreshold: 3,
        MaxHalfOpen:      5,
        Timeout:          300, // Timeout in seconds
    }

    cb := clients.NewCB(breakerInfo)

    for i := 0; i < 10; i++ {
        err := cb.CanExecute()
        if err != nil {
            fmt.Println("Circuit breaker is open. Cannot execute operation.")
            continue
        }

        err = performOperation()
        cb.OnExecution(err == nil)
        if err != nil {
            fmt.Printf("Operation failed: %v\n", err)
        } else {
            fmt.Println("Operation succeeded")
        }
    }
}

func performOperation() error {
    // Simulate an operation that may fail
    return fmt.Errorf("simulated error")
}

Installation

go get oss.nandlabs.io/golly/clients