New Upstream Release - golang-gopkg-eapache-go-resiliency.v1

Ready changes

Summary

Merged new upstream version: 1.3.0 (was: 1.2.0).

Resulting package

Built on 2022-12-14T15:01 (took 3m30s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-releases golang-gopkg-eapache-go-resiliency.v1-dev

Lintian Result

Diff

diff --git a/.github/workflows/golang-ci.yml b/.github/workflows/golang-ci.yml
new file mode 100644
index 0000000..b2d5179
--- /dev/null
+++ b/.github/workflows/golang-ci.yml
@@ -0,0 +1,24 @@
+name: Golang CI
+
+on: [push, pull_request]
+
+jobs:
+  build:
+    runs-on: ubuntu-latest
+    strategy:
+      matrix:
+        go-version: [1.13, 1.18]
+
+    steps:
+      - uses: actions/checkout@v3
+
+      - name: Set up Go
+        uses: actions/setup-go@v3
+        with:
+          go-version: ${{ matrix.go-version }}
+
+      - name: Build
+        run: go build -v ./...
+
+      - name: Test
+        run: go test -v ./...
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 21008c3..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-language: go
-
-go:
-  - 1.7
-  - 1.12
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 66e1857..f0d44b0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,11 +1,23 @@
 # Changelog
 
-#### Version 1.2.0 (2019-06-14)
+*Note: I will occasionally bump the minimum required Golang version without
+bumping the major version of this package, which violates the official Golang
+packaging convention around breaking changes. Typically the versions being
+dropped are multiple years old and long unsupported.*
+
+#### Version 1.3.0 (2022-06-27)
 
-*Note: This release requires Golang at least 1.7, which is higher than the
-previous release. All the versions being dropped are multiple years old and no
-longer supported upstream, so I'm not counting this as a breaking change.*
+ - Increased minimum Golang version to 1.13.
+ - Fix a goroutine leak in `Deadline.Run()` on `ErrTimeOut`.
+ - Add a `go.mod` file to conform to more recent Golang version standards.
+ - Use `errors.Is` when classifying errors for the `Retrier` (thanks to Taufik
+   Rama).
+ - Add implementation of `LimitedExponentialBackoff` for the `Retrier` (thanks
+   to tukeJonny).
+
+#### Version 1.2.0 (2019-06-14)
 
+ - Increased minimum Golang version to 1.7.
  - Add `RunCtx` method on `Retrier` to support running with a context.
  - Ensure the `Retrier`'s use of random numbers is concurrency-safe.
  - Bump CI to ensure we support newer Golang versions.
diff --git a/README.md b/README.md
index 0a0d701..86368ec 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
 go-resiliency
 =============
 
-[![Build Status](https://travis-ci.org/eapache/go-resiliency.svg?branch=master)](https://travis-ci.org/eapache/go-resiliency)
+[![Golang CI](https://github.com/eapache/go-resiliency/actions/workflows/golang-ci.yml/badge.svg)](https://github.com/eapache/go-resiliency/actions/workflows/golang-ci.yml)
 [![GoDoc](https://godoc.org/github.com/eapache/go-resiliency?status.svg)](https://godoc.org/github.com/eapache/go-resiliency)
 [![Code of Conduct](https://img.shields.io/badge/code%20of%20conduct-active-blue.svg)](https://eapache.github.io/conduct.html)
 
@@ -16,6 +16,7 @@ Currently implemented patterns include:
 - batching (in the `batcher` directory)
 - retriable (in the `retrier` directory)
 
-Follows semantic versioning using https://gopkg.in/ - import from
-[`gopkg.in/eapache/go-resiliency.v1`](https://gopkg.in/eapache/go-resiliency.v1)
-for guaranteed API stability.
+*Note: I will occasionally bump the minimum required Golang version without
+bumping the major version of this package, which violates the official Golang
+packaging convention around breaking changes. Typically the versions being
+dropped are multiple years old and long unsupported.*
diff --git a/deadline/deadline.go b/deadline/deadline.go
index 3a6dfb0..c97fd86 100644
--- a/deadline/deadline.go
+++ b/deadline/deadline.go
@@ -32,7 +32,11 @@ func (d *Deadline) Run(work func(<-chan struct{}) error) error {
 	stopper := make(chan struct{})
 
 	go func() {
-		result <- work(stopper)
+		value := work(stopper)
+		select {
+		case result <- value:
+		case <-stopper:
+		}
 	}()
 
 	select {
diff --git a/debian/changelog b/debian/changelog
index fd940f0..f139dc5 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+golang-gopkg-eapache-go-resiliency.v1 (1.3.0-1) UNRELEASED; urgency=low
+
+  * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Wed, 14 Dec 2022 14:58:46 -0000
+
 golang-gopkg-eapache-go-resiliency.v1 (1.2.0-1) unstable; urgency=medium
 
   [ Debian Janitor ]
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..11f4ca3
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,3 @@
+module github.com/eapache/go-resiliency
+
+go 1.13
diff --git a/retrier/backoffs.go b/retrier/backoffs.go
index faf6f8c..cf04f60 100644
--- a/retrier/backoffs.go
+++ b/retrier/backoffs.go
@@ -22,3 +22,20 @@ func ExponentialBackoff(n int, initialAmount time.Duration) []time.Duration {
 	}
 	return ret
 }
+
+// LimitedExponentialBackoff generates a simple back-off strategy of retrying 'n' times, and doubling the amount of
+// time waited after each one.
+// If back-off reaches `limitAmount` , thereafter back-off will be filled with `limitAmount` .
+func LimitedExponentialBackoff(n int, initialAmount time.Duration, limitAmount time.Duration) []time.Duration {
+	ret := make([]time.Duration, n)
+	next := initialAmount
+	for i := range ret {
+		if next < limitAmount {
+			ret[i] = next
+			next *= 2
+		} else {
+			ret[i] = limitAmount
+		}
+	}
+	return ret
+}
diff --git a/retrier/backoffs_test.go b/retrier/backoffs_test.go
index 1168adf..ca323b8 100644
--- a/retrier/backoffs_test.go
+++ b/retrier/backoffs_test.go
@@ -53,3 +53,33 @@ func TestExponentialBackoff(t *testing.T) {
 		t.Error("incorrect value")
 	}
 }
+
+func TestLimitedExponentialBackoff(t *testing.T) {
+	b := LimitedExponentialBackoff(1, 10*time.Millisecond, 11*time.Millisecond)
+	if len(b) != 1 {
+		t.Error("incorrect length")
+	}
+	if b[0] != 10*time.Millisecond {
+		t.Error("incorrect value")
+	}
+
+	b = LimitedExponentialBackoff(5, 1*time.Minute, 4*time.Minute)
+	if len(b) != 5 {
+		t.Error("incorrect length")
+	}
+	if b[0] != 1*time.Minute {
+		t.Error("incorrect value")
+	}
+	if b[1] != 2*time.Minute {
+		t.Error("incorrect value")
+	}
+	if b[2] != 4*time.Minute {
+		t.Error("incorrect value")
+	}
+	if b[3] != 4*time.Minute {
+		t.Error("incorrect value")
+	}
+	if b[4] != 4*time.Minute {
+		t.Error("incorrect value")
+	}
+}
diff --git a/retrier/classifier.go b/retrier/classifier.go
index 7dd71c7..20d5a73 100644
--- a/retrier/classifier.go
+++ b/retrier/classifier.go
@@ -1,5 +1,7 @@
 package retrier
 
+import "errors"
+
 // Action is the type returned by a Classifier to indicate how the Retrier should proceed.
 type Action int
 
@@ -38,7 +40,7 @@ func (list WhitelistClassifier) Classify(err error) Action {
 	}
 
 	for _, pass := range list {
-		if err == pass {
+		if errors.Is(err, pass) {
 			return Retry
 		}
 	}
@@ -57,7 +59,7 @@ func (list BlacklistClassifier) Classify(err error) Action {
 	}
 
 	for _, pass := range list {
-		if err == pass {
+		if errors.Is(err, pass) {
 			return Fail
 		}
 	}
diff --git a/retrier/classifier_test.go b/retrier/classifier_test.go
index 953102f..46b5ce0 100644
--- a/retrier/classifier_test.go
+++ b/retrier/classifier_test.go
@@ -29,6 +29,18 @@ func TestDefaultClassifier(t *testing.T) {
 	}
 }
 
+type wrappedErr struct {
+	error
+}
+
+func (w wrappedErr) Error() string {
+	return "there's an error happening during X: " + w.Error()
+}
+
+func (w wrappedErr) Unwrap() error {
+	return w.error
+}
+
 func TestWhitelistClassifier(t *testing.T) {
 	c := WhitelistClassifier{errFoo, errBar}
 
@@ -45,6 +57,16 @@ func TestWhitelistClassifier(t *testing.T) {
 	if c.Classify(errBaz) != Fail {
 		t.Error("whitelist misclassified baz")
 	}
+
+	if c.Classify(wrappedErr{error: errFoo}) != Retry {
+		t.Error("whitelist misclassified foo")
+	}
+	if c.Classify(wrappedErr{error: errBar}) != Retry {
+		t.Error("whitelist misclassified bar")
+	}
+	if c.Classify(wrappedErr{error: errBaz}) != Fail {
+		t.Error("whitelist misclassified baz")
+	}
 }
 
 func TestBlacklistClassifier(t *testing.T) {
@@ -63,4 +85,14 @@ func TestBlacklistClassifier(t *testing.T) {
 	if c.Classify(errBaz) != Retry {
 		t.Error("blacklist misclassified baz")
 	}
+
+	if c.Classify(wrappedErr{error: errFoo}) != Retry {
+		t.Error("blacklist misclassified foo")
+	}
+	if c.Classify(wrappedErr{error: errBar}) != Fail {
+		t.Error("blacklist misclassified bar")
+	}
+	if c.Classify(wrappedErr{error: errBaz}) != Retry {
+		t.Error("blacklist misclassified baz")
+	}
 }

Debdiff

[The following lists of changes regard files as different if they have different names, permissions or owners.]

Files in second set of .debs but not in first

-rw-r--r--  root/root   /usr/share/gocode/src/gopkg.in/eapache/go-resiliency.v1/go.mod

No differences were encountered in the control files

More details

Full run details