retry

🔄 Retry Package

The Retry Package provides a robust and extensible interface for automatically retrying operations in Go. It supports configurable retry strategies like fixed delays, jitter, and exponential backoff, ensuring reliability in API calls, database queries, and distributed systems.

Features

  • Customizable Backoff Strategies – Supports Fixed, Jitter, and Exponential backoff

  • Context-Aware – Automatically stops retries when the context is canceled

  • Configurable Retry Conditions – Choose which errors should trigger retries

Installation

go get github.com/kittipat1413/go-common/framework/retry

Documentation

For detailed API documentation, examples, and usage patterns, visit the Go Package Documentation.

Usage

🧩 Interface

type Retrier interface {
    ExecuteWithRetry(ctx context.Context, fn RetryFunc, retryOn RetryOnFunc) error
}

ExecuteWithRetry: Executes a function with automatic retry logic.

  • Params:

    • ctx: Context for request tracing and cancellation

    • fn: The function to retry (must return an error if it fails)

    • retryOn: Custom function to determine retry conditions

  • Returns:

    • error: The final result after retries.

Example: Basic Retry

package main

import (
	"context"
	"errors"
	"fmt"
	"log"
	"time"

	"github.com/kittipat1413/go-common/framework/retry"
)

func main() {
	ctx := context.Background()

	// Define backoff strategy
	backoff, err := retry.NewFixedBackoffStrategy(2 * time.Second)
	if err != nil {
		log.Fatalf("Failed to create backoff strategy: %v", err)
	}
	// Define retry configuration
	config := retry.Config{
		MaxAttempts: 3,
		Backoff:     backoff,
	}
	// Create Retrier
	retrier, err := retry.NewRetrier(config)
	if err != nil {
		log.Fatalf("Failed to create retrier: %v", err)
	}

	// Execute function with retry logic
	err = retrier.ExecuteWithRetry(ctx, func(ctx context.Context) error {
		fmt.Println("Attempting API request...")
		return errors.New("network timeout")
	}, func(attempt int, err error) bool {
		fmt.Printf("Retry %d due to: %v\n", attempt, err)
		return err.Error() == "network timeout" // Retry only for network timeouts
	})

	if err != nil {
		fmt.Println("Final failure:", err)
	} else {
		fmt.Println("Operation succeeded!")
	}
}

You can find a complete working example in the repository under framework/retry/example.

Backoff Strategies

1. Fixed Backoff

backoff, _ := retry.NewFixedBackoffStrategy(2 * time.Second)
  • Constant delay between retries

  • Simple and predictable retry behavior

2. Jitter Backoff

backoff, _ := retry.NewJitterBackoffStrategy(2*time.Second, 500*time.Millisecond)
  • Adds randomness to prevent synchronized retries (thundering herd problem)

3. Exponential Backoff

backoff, _ := retry.NewExponentialBackoffStrategy(
	100*time.Millisecond, // base
	2.0,                  // factor
	5*time.Second,        // upper limit of delay
)
  • Delays grow exponentially (BaseDelay * Factor^attempt)

  • Prevents excessive load on failing services

Last updated