backoff

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Dec 1, 2025 License: MIT Imports: 4 Imported by: 0

README

GoDoc reference Lint Test

Backoff

Package backoff implements backoff logic for retry loops.

It provides a Generator that produces a sequence of time.Duration values using configurable step functions: Fixed, Linear, Incremental, Exponential, and Jitter.

Usage

Exponential Backoff
gen := backoff.New(time.Second, 30*time.Second, backoff.Exponential(2))

for attempt := range gen.Values() {
    if err := doSomething(); err == nil {
        break
    }
    time.Sleep(attempt)
}
// Produces: 1s, 2s, 4s, 8s, 16s, 30s, 30s, ...
With Jitter

Jitter is useful in distributed systems to avoid thundering herd problems.

gen := backoff.New(
    time.Second,
    30*time.Second,
    backoff.Jitter(backoff.Exponential(2), 0.5),
)

for i := 0; i < maxRetries; i++ {
    if err := doSomething(); err == nil {
        break
    }
    time.Sleep(gen.Next())
}
// Produces values in range: [0.5s-1s], [1s-2s], [2s-4s], ...
Linear Backoff
gen := backoff.New(time.Second, 10*time.Second, backoff.Linear(2*time.Second))
// Produces: 1s, 3s, 5s, 7s, 9s, 10s, 10s, ...
Fixed Backoff
gen := backoff.New(time.Second, 0, backoff.Fixed(5*time.Second))
// Produces: 5s, 5s, 5s, ...

Step Functions

Function Description
Fixed(d) Always returns d
Linear(d) Adds d each iteration: base, base+d, base+2d, ...
Incremental(m) Multiplies base by count: base, base*m, base*2m, ...
Exponential(f) Exponential growth: base, base*f, base*f^2, ...
Jitter(fn, factor) Wraps any step function with randomized jitter in [d-factor*d, d]

Contributions

Contributions are welcome via Pull Requests.

Documentation

Overview

Package backoff implements backoff logic for loop controls.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Generator

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

Generator generates a sequence of duration values using a step function.

A Generator is not safe for concurrent use by multiple goroutines.

func New

func New(base, ceiling time.Duration, fn StepFunc) *Generator

New returns a new generator that uses the given step function.

Base is the first value that will be returned, and the one from which the next values will be derived. Ceiling is the maximum value that can be generated. A ceiling of 0 disables the ceiling check.

func (*Generator) Ceiling

func (g *Generator) Ceiling() time.Duration

Ceiling returns the highest duration that can be returned by [Next].

func (*Generator) Next

func (g *Generator) Next() time.Duration

Next generates and returns the next duration.

func (*Generator) Reset

func (g *Generator) Reset()

Reset resets the generator to its initial state.

func (*Generator) Values

func (g *Generator) Values() iter.Seq[time.Duration]

Values implements an infinite iterator over the generator.

type StepFunc

type StepFunc func(base time.Duration, count int) time.Duration

StepFunc is the signature of the function that generates step values for a Generator.

func Exponential

func Exponential(factor int) StepFunc

Exponential returns an exponential step function.

Example

Example of a exponential backoff.

package main

import (
	"fmt"
	"time"

	"mz.attahri.com/code/backoff"
)

func main() {
	gen := backoff.New(time.Second, 30*time.Second, backoff.Exponential(2))
	values := make([]time.Duration, 10)
	for i := range len(values) {
		values[i] = gen.Next().Truncate(time.Second)
	}
	fmt.Println(values)
}
Output:

[1s 2s 4s 8s 16s 30s 30s 30s 30s 30s]

func Fixed

func Fixed(d time.Duration) StepFunc

Fixed returns a StepFunc that always returns the same duration.

Example

Example of a fixed backoff.

package main

import (
	"fmt"
	"time"

	"mz.attahri.com/code/backoff"
)

func main() {
	gen := backoff.New(time.Second, 10*time.Second, backoff.Fixed(time.Second))
	values := make([]time.Duration, 5)
	for i := range len(values) {
		values[i] = gen.Next()
	}
	fmt.Println(values)
}
Output:

[1s 1s 1s 1s 1s]

func Incremental

func Incremental(multiplier int) StepFunc

Incremental returns a step function that scales the base by the given multiple each retry.

Example

Example of an incremental backoff.

package main

import (
	"fmt"
	"time"

	"mz.attahri.com/code/backoff"
)

func main() {
	gen := backoff.New(time.Second, 10*time.Second, backoff.Incremental(2))
	values := make([]time.Duration, 10)
	for i := range len(values) {
		values[i] = gen.Next()
	}
	fmt.Println(values)
}
Output:

[1s 2s 4s 6s 8s 10s 10s 10s 10s 10s]

func Jitter

func Jitter(fn StepFunc, factor float64) StepFunc

Jitter wraps a StepFunc and returns a new StepFunc that applies "full-range" jitter in the range [d - factor*d, d].

For example, with d=1s and factor=0.5, the result is uniformly distributed in [500ms, 1s]. Factor should be in [0, 1].

Example

Jitter is particularly useful with distributed systems.

package main

import (
	"fmt"
	"time"

	"mz.attahri.com/code/backoff"
)

func main() {
	gen := backoff.New(time.Second, 30*time.Second, backoff.Jitter(backoff.Exponential(2), 0.5))
	values := make([]time.Duration, 5)
	for i := range len(values) {
		values[i] = gen.Next().Truncate(time.Second)
	}
	fmt.Println(values)
}

func Linear

func Linear(d time.Duration) StepFunc

Linear returns a step function that adds d each retry.

Example

Example of a linear backoff.

package main

import (
	"fmt"
	"time"

	"mz.attahri.com/code/backoff"
)

func main() {
	gen := backoff.New(time.Second, 10*time.Second, backoff.Linear(2*time.Second))
	values := make([]time.Duration, 5)
	for i := range len(values) {
		values[i] = gen.Next()
	}
	fmt.Println(values)
}
Output:

[1s 3s 5s 7s 9s]

Jump to

Keyboard shortcuts

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