From a21a7b7d8efe5b594791153e7141b4e58246b299 Mon Sep 17 00:00:00 2001 From: Kostiantyn Masliuk <1pkg@protonmail.com> Date: Mon, 19 Oct 2020 19:17:43 +0200 Subject: [PATCH] add retry throttler --- README.MD | 1 + runnables.go => executors.go | 0 throttlers.go | 23 +++++++++++++++++++++++ throttlers_test.go | 23 +++++++++++++++++++++-- 4 files changed, 45 insertions(+), 2 deletions(-) rename runnables.go => executors.go (100%) diff --git a/README.MD b/README.MD index 926ff5b..7d1e26f 100644 --- a/README.MD +++ b/README.MD @@ -159,6 +159,7 @@ thr := NewThrottlerAll( // throttles only if all children throttle | any | `func NewThrottlerAny(thrs ...Throttler) Throttler` | Throttles call if any of provided throttlers throttle. | | not | `func NewThrottlerNot(thr Throttler) Throttler` | Throttles call if provided throttler doesn't throttle. | | suppress | `func NewThrottlerSuppress(thr Throttler) Throttler` | Suppresses provided throttler to never throttle. | +| retry | `func NewThrottlerRetry(thr Throttler, retries uint64) Throttler` | Retries provided throttler error up until the provided retries threshold.
Internally retry uses square throttler with `DefaultRetriedDuration` initial duration. | ## Integrations diff --git a/runnables.go b/executors.go similarity index 100% rename from runnables.go rename to executors.go diff --git a/throttlers.go b/throttlers.go index 726e098..563b3cb 100644 --- a/throttlers.go +++ b/throttlers.go @@ -770,3 +770,26 @@ func (thr tsuppress) Release(ctx context.Context) error { _ = thr.thr.Release(ctx) return nil } + +type tretry struct { + thr Throttler + retries uint64 +} + +// NewThrottlerRetry creates new throttler instance that +// retries provided throttler error up until the provided retries threshold. +// Internally retry uses square throttler with `DefaultRetriedDuration` initial duration. +func NewThrottlerRetry(thr Throttler, retries uint64) Throttler { + return tretry{thr: thr, retries: retries} +} + +func (thr tretry) Acquire(ctx context.Context) error { + return retried(thr.retries, func(ctx context.Context) error { + return thr.thr.Acquire(ctx) + })(ctx) +} + +func (thr tretry) Release(ctx context.Context) error { + _ = thr.thr.Release(ctx) + return nil +} diff --git a/throttlers_test.go b/throttlers_test.go index 339379e..67f242e 100644 --- a/throttlers_test.go +++ b/throttlers_test.go @@ -102,6 +102,7 @@ func (t *tcase) result(index int) (dur time.Duration, err error) { } func TestThrottlers(t *testing.T) { + DefaultRetriedDuration = time.Millisecond cctx, cancel := context.WithCancel(context.Background()) cancel() table := map[string]tcase{ @@ -774,14 +775,32 @@ func TestThrottlers(t *testing.T) { errors.New("throttler hasn't received any internal error"), }, }, - "Throttler suppress should not throttle on internal errors": { + "Throttler suppress should not throttle on internal error": { tms: 3, thr: NewThrottlerSuppress(NewThrottlerEcho(errors.New("test"))), }, - "Throttler suppress should throttle on non internal errors": { + "Throttler suppress should throttle on non internal error": { tms: 3, thr: NewThrottlerSuppress(NewThrottlerEcho(nil)), }, + "Throttler retry should throttle on recuring internal error": { + tms: 3, + thr: NewThrottlerRetry(NewThrottlerEcho(errors.New("test")), 2), + errs: []error{ + errors.New("test"), + errors.New("test"), + errors.New("test"), + }, + }, + "Throttler retry should not throttle on retried recuring internal error": { + tms: 3, + thr: NewThrottlerRetry(NewThrottlerAfter(3), 2), + errs: []error{ + errors.New("test"), + nil, + nil, + }, + }, } for tname, ptrtcase := range table { t.Run(tname, func(t *testing.T) {