backoff

package module
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: Sep 25, 2024 License: Apache-2.0 Imports: 5 Imported by: 0

README

backoff

backoff is a Go package that provides iterators powered by github.com/cenkalti/backoff/v4.

Go Reference Go Report Card

It offers a flexible and easy-to-use way to implement various backoff strategies in your Go applications.

Features

  • Easy integration with Go's for range statements
  • Supports multiple backoff policies:
    • Stop BackOff
    • Zero BackOff
    • Constant BackOff
    • Exponential BackOff
  • Context-aware for graceful cancellation
  • Customizable options for fine-tuning backoff behavior
  • All of BackOff's features come from github.com/cenkalti/backoff/v4, which is used by many.

Installation

To install backoff, use go get:

go get github.com/goaux/backoff

Usage

Here's a basic example of how to use backoff:

package main

import (
    "context"
    "fmt"
    "time"

    "github.com/goaux/backoff"
)

func main() {
    exponentialBackOff := backoff.NewExponential(
        backoff.WithInitialInterval(100 * time.Millisecond),
        backoff.WithMaxRetries(5),
    )
    ctx := context.Background()
    for i := range exponentialBackOff(ctx) {
        fmt.Printf("Attempt %d\n", i)
        // Perform your operation here
        // Break the loop if the operation succeeds
    }
}

License

This project is licensed under the Apache-2.0.

Special Thanks

@cenkalti https://github.com/cenkalti/backoff

Documentation

Overview

Package backoff provides iterators powered by github.com/cenkalti/backoff/v4.

This package provides the type BackOff and BackOffDuration, which creates an iterator powered by github.com/cenkalti/backoff/v4.

BackOff is used to configure a run-and-wait loop, and BackOffDuration is used to generate a sequence of wait times.

BackOff can be created by NewConstant and NewExponential.

BackOffDuration can be created by NewConstantDuration and NewExponentialDuration.

There are four policies.

Iteratros powered by StopBackOff, ZeroBackOff and ConstantBackOff can be created from NewConstant and NewConstantDuration.

Iterators powered by ExponentialBackOff can be created from NewExponential and NewExponentialDuration.

Iterators are used in `for statements with range clause` so that iteration can be easily terminated with `break`. Alternatively, you can use WithMaxRetries to limit the number of retries.

You can interrupt the wait by canceling the context you specified when creating the iterator, idiomatically.

See

Example
package main

import (
	"context"
	"fmt"
	"time"

	"github.com/goaux/backoff"
)

func main() {
	ctx := context.TODO()
	unit := 100 * time.Millisecond

	// [ExponentialBackOff](https://pkg.go.dev/github.com/cenkalti/backoff/v4#ExponentialBackOff)
	exponentialBackOff := backoff.NewExponential(
		backoff.WithInitialInterval(unit),
		backoff.WithRandomizationFactor(0), // Set to 0 for demonstrative purpose.
		backoff.WithMaxRetries(7),
	)
	start := time.Now()
	for i := range exponentialBackOff(ctx) {
		fmt.Println("task", i, (time.Since(start) / unit * unit).String())
		if false { // Here we assume the task will always fail, so no break will occur.
			break
		}
	}
}
Output:

task 0 0s
task 1 100ms
task 2 200ms
task 3 400ms
task 4 800ms
task 5 1.3s
task 6 2s
task 7 3.2s

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type BackOff

type BackOff func(context.Context) iter.Seq[int]

BackOff is a function to create an iterator. The iterator can be cancelled by a context. It is safe to pass nil for the context when creating an iterator. The iterator yields sequence of integers representing the number of retry attempts.

func NewConstant

func NewConstant(interval time.Duration, options ...ConstantOption) BackOff

NewConstant returns a BackOff, which creates an iterator with a backoff policy that always returns the same backoff delay.

If interval < 0 then NewConstant returns the iterator powered by backoff.StopBackOff.

If interval == 0 then NewConstant returns the iterator powered by backoff.ZeroBackOff.

If interval > 0 then NewConstant returns the iterator powered by backoff.ConstantBackOff.

Example
package main

import (
	"context"
	"fmt"
	"time"

	"github.com/goaux/backoff"
)

func main() {
	ctx := context.TODO()
	unit := 100 * time.Millisecond

	// interval > 0
	// [ConstantBackOff](https://pkg.go.dev/github.com/cenkalti/backoff/v4#ConstantBackOff)
	constant := backoff.NewConstant(2*unit, backoff.WithMaxRetries(5))
	start := time.Now()
	for i := range constant(ctx) {
		fmt.Println("constant#false", i, (time.Since(start) / unit * unit).String())
		if false {
			break
		}
	}
	start = time.Now()
	for i := range constant(ctx) {
		fmt.Println("constant#true", i, (time.Since(start) / unit * unit).String())
		if true {
			break
		}
	}
}
Output:

constant#false 0 0s
constant#false 1 200ms
constant#false 2 400ms
constant#false 3 600ms
constant#false 4 800ms
constant#false 5 1s
constant#true 0 0s
Example (CancelContext)
package main

import (
	"context"
	"fmt"
	"time"

	"github.com/goaux/backoff"
)

func main() {
	ctx := context.TODO()
	unit := 100 * time.Millisecond

	// interval > 0
	// [ConstantBackOff](https://pkg.go.dev/github.com/cenkalti/backoff/v4#ConstantBackOff)
	constantBackOff := backoff.NewConstant(2*unit, backoff.WithMaxRetries(5))
	start := time.Now()
	ctx, cancel := context.WithTimeout(ctx, 3*unit)
	defer cancel()
	for i := range constantBackOff(ctx) {
		fmt.Println("constant#false", i, (time.Since(start) / unit * unit).String())
		if false {
			break
		}
	}
	fmt.Println("cancel", (time.Since(start) / unit * unit).String())
}
Output:

constant#false 0 0s
constant#false 1 200ms
cancel 300ms
Example (StopBackOff)
package main

import (
	"context"
	"fmt"
	"time"

	"github.com/goaux/backoff"
)

func main() {
	ctx := context.TODO()
	unit := 100 * time.Millisecond

	// interval < 0
	// [StopBackOff](https://pkg.go.dev/github.com/cenkalti/backoff/v4#StopBackOff)
	constantBackOff := backoff.NewConstant(-1, backoff.WithMaxRetries(3))
	start := time.Now()
	for i := range constantBackOff(ctx) {
		fmt.Println("stop#false", i, (time.Since(start) / unit * unit).String())
		if false {
			break
		}
	}
	start = time.Now()
	for i := range constantBackOff(ctx) {
		fmt.Println("stop#true", i, (time.Since(start) / unit * unit).String())
		if true {
			break
		}
	}
}
Output:

stop#false 0 0s
stop#true 0 0s
Example (ZeroBackOff)
package main

import (
	"context"
	"fmt"
	"time"

	"github.com/goaux/backoff"
)

func main() {
	ctx := context.TODO()
	unit := 100 * time.Millisecond

	// interval == 0
	// [ZeroBackOff](https://pkg.go.dev/github.com/cenkalti/backoff/v4#ZeroBackOff)
	constantBackOff := backoff.NewConstant(0, backoff.WithMaxRetries(4))
	start := time.Now()
	for i := range constantBackOff(ctx) {
		fmt.Println("zero#false", i, (time.Since(start) / unit * unit).String())
		if false {
			break
		}
	}
	start = time.Now()
	for i := range constantBackOff(ctx) {
		fmt.Println("zero#true", i, (time.Since(start) / unit * unit).String())
		if true {
			break
		}
	}
}
Output:

zero#false 0 0s
zero#false 1 0s
zero#false 2 0s
zero#false 3 0s
zero#false 4 0s
zero#true 0 0s

func NewExponential

func NewExponential(options ...ExponentialOption) BackOff

NewExponential returns a BackOff, which creates an iterator powered by backoff.ExponentialBackOff.

Example
package main

import (
	"context"
	"fmt"
	"time"

	"github.com/goaux/backoff"
)

func main() {
	ctx := context.TODO()
	unit := 50 * time.Millisecond

	// [ExponentialBackOff](https://pkg.go.dev/github.com/cenkalti/backoff/v4#ExponentialBackOff)
	exponentialBackOff := backoff.NewExponential(
		backoff.WithInitialInterval(2*unit),
		backoff.WithRandomizationFactor(0), // Set to 0 for demonstrative purpose.
		backoff.WithMaxRetries(7),
	)
	start := time.Now()
	for i := range exponentialBackOff(ctx) {
		fmt.Println("exponential#false", i, (time.Since(start) / unit * unit).String())
		if false {
			break
		}
	}
	start = time.Now()
	for i := range exponentialBackOff(ctx) {
		fmt.Println("exponential#true", i, (time.Since(start) / unit * unit).String())
		if true {
			break
		}
	}
}
Output:

exponential#false 0 0s
exponential#false 1 100ms
exponential#false 2 250ms
exponential#false 3 450ms
exponential#false 4 800ms
exponential#false 5 1.3s
exponential#false 6 2.05s
exponential#false 7 3.2s
exponential#true 0 0s
Example (CancelContext)
package main

import (
	"context"
	"fmt"
	"time"

	"github.com/goaux/backoff"
)

func main() {
	ctx := context.TODO()
	unit := 50 * time.Millisecond

	// [ExponentialBackOff](https://pkg.go.dev/github.com/cenkalti/backoff/v4#ExponentialBackOff)
	exponentialBackOff := backoff.NewExponential(
		backoff.WithInitialInterval(2*unit),
		backoff.WithRandomizationFactor(0), // Set to 0 for demonstrative purpose.
		backoff.WithMaxRetries(7),
	)
	start := time.Now()
	ctx, cancel := context.WithTimeout(ctx, 3*unit)
	defer cancel()
	for i := range exponentialBackOff(ctx) {
		fmt.Println("exponential#false", i, (time.Since(start) / unit * unit).String())
		if false {
			break
		}
	}
	fmt.Println("cancel", (time.Since(start) / unit * unit).String())
}
Output:

exponential#false 0 0s
exponential#false 1 100ms
cancel 150ms

type BackOffDuration added in v1.1.0

type BackOffDuration func() iter.Seq2[int, time.Duration]

BackOffDuration is a function to create an iterator that emits interval durations.

func NewConstantDuration added in v1.1.0

func NewConstantDuration(
	interval time.Duration,
	options ...ConstantOption,
) BackOffDuration

NewConstantDuration returns a BackOffDuration, which creates an iterator with a backoff policy that always returns the same backoff delay.

If interval < 0 then NewConstantDuration returns the iterator powered by backoff.StopBackOff.

If interval == 0 then NewConstantDuration returns the iterator powered by backoff.ZeroBackOff.

If interval > 0 then NewConstantDuration returns the iterator powered by backoff.ConstantBackOff.

Example
package main

import (
	"fmt"
	"time"

	"github.com/goaux/backoff"
)

func main() {
	backOffDuration := backoff.NewConstantDuration(42*time.Second, backoff.WithMaxRetries(5))
	for i, d := range backOffDuration() {
		fmt.Println(i, d.String())
	}
}
Output:

0 42s
1 42s
2 42s
3 42s
4 42s

func NewExponentialDuration added in v1.1.0

func NewExponentialDuration(
	options ...ExponentialOption,
) BackOffDuration

NewExponentialDuration returns a BackOffDuration, which creates an iterator powered by backoff.ExponentialBackOff.

Example
package main

import (
	"fmt"
	"time"

	"github.com/goaux/backoff"
)

func main() {
	backOffDuration := backoff.NewExponentialDuration(
		backoff.WithInitialInterval(10*time.Second),
		backoff.WithRandomizationFactor(0),
		backoff.WithMaxRetries(5),
	)
	for i, d := range backOffDuration() {
		fmt.Println(i, d.String())
	}
}
Output:

0 10s
1 15s
2 22.5s
3 33.75s
4 50.625s

type ConstantOption

type ConstantOption interface {
	// contains filtered or unexported methods
}

ConstantOption is a optional parameter for NewConstant.

type ExponentialOption

type ExponentialOption interface {
	// contains filtered or unexported methods
}

ExponentialOption is a optional parameter for NewExponential.

The following options are available:

See backoff.ExponentialBackOff for more details on each option.

func WithClockProvider

func WithClockProvider(c backoff.Clock) ExponentialOption

WithClockProvider sets the clock used to measure time.

See backoff.WithClockProvider.

func WithInitialInterval

func WithInitialInterval(d time.Duration) ExponentialOption

WithInitialInterval sets the initial interval between retries.

See backoff.WithInitialInterval.

func WithMaxElapsedTime

func WithMaxElapsedTime(d time.Duration) ExponentialOption

WithMaxElapsedTime sets the maximum total time for retries.

See backoff.WithMaxElapsedTime.

func WithMaxInterval

func WithMaxInterval(d time.Duration) ExponentialOption

WithMaxInterval sets the maximum interval between retries.

See backoff.WithMaxInterval.

func WithMultiplier

func WithMultiplier(v float64) ExponentialOption

WithMultiplier sets the multiplier for increasing the interval after each retry.

See backoff.WithMultiplier.

func WithRandomizationFactor

func WithRandomizationFactor(v float64) ExponentialOption

WithRandomizationFactor sets the randomization factor to add jitter to intervals.

See backoff.WithRandomizationFactor.

func WithRetryStopDuration

func WithRetryStopDuration(d time.Duration) ExponentialOption

WithRetryStopDuration sets the duration after which retries should stop.

See backoff.WithRetryStopDuration.

type Option

type Option interface {
	ConstantOption
	ExponentialOption
}

Option is a optional parameter for NewConstant and NewExponential.

func WithMaxRetries

func WithMaxRetries(max uint64) Option

WithMaxRetries sets the upper limit of the retry loop count.

See backoff.WithMaxRetries.

Jump to

Keyboard shortcuts

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