From 94027eb4ad01c501c0778dfa0984366759ef0a9d Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Fri, 3 Nov 2023 08:22:42 -0500 Subject: [PATCH] pkg/services: add StopChan & StopRChan from core (#213) --- pkg/services/stop.go | 50 ++++++++++++++++++++++++++++++++++++++++++++ pkg/utils/utils.go | 12 +++-------- 2 files changed, 53 insertions(+), 9 deletions(-) create mode 100644 pkg/services/stop.go diff --git a/pkg/services/stop.go b/pkg/services/stop.go new file mode 100644 index 0000000000..900ec6c846 --- /dev/null +++ b/pkg/services/stop.go @@ -0,0 +1,50 @@ +package services + +import "context" + +// A StopChan signals when some work should stop. +// Use StopChanR if you already have a read only <-chan. +type StopChan chan struct{} + +// NewCtx returns a background [context.Context] that is cancelled when StopChan is closed. +func (s StopChan) NewCtx() (context.Context, context.CancelFunc) { + return StopRChan((<-chan struct{})(s)).NewCtx() +} + +// Ctx cancels a [context.Context] when StopChan is closed. +func (s StopChan) Ctx(ctx context.Context) (context.Context, context.CancelFunc) { + return StopRChan((<-chan struct{})(s)).Ctx(ctx) +} + +// CtxCancel cancels a [context.Context] when StopChan is closed. +// Returns ctx and cancel unmodified, for convenience. +func (s StopChan) CtxCancel(ctx context.Context, cancel context.CancelFunc) (context.Context, context.CancelFunc) { + return StopRChan((<-chan struct{})(s)).CtxCancel(ctx, cancel) +} + +// A StopRChan signals when some work should stop. +// This is a receive-only version of StopChan, for casting an existing <-chan. +type StopRChan <-chan struct{} + +// NewCtx returns a background [context.Context] that is cancelled when StopChan is closed. +func (s StopRChan) NewCtx() (context.Context, context.CancelFunc) { + return s.Ctx(context.Background()) +} + +// Ctx cancels a [context.Context] when StopChan is closed. +func (s StopRChan) Ctx(ctx context.Context) (context.Context, context.CancelFunc) { + return s.CtxCancel(context.WithCancel(ctx)) +} + +// CtxCancel cancels a [context.Context] when StopChan is closed. +// Returns ctx and cancel unmodified, for convenience. +func (s StopRChan) CtxCancel(ctx context.Context, cancel context.CancelFunc) (context.Context, context.CancelFunc) { + go func() { + select { + case <-s: + cancel() + case <-ctx.Done(): + } + }() + return ctx, cancel +} diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index aed521c621..4f17144e85 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -5,6 +5,8 @@ import ( "math" mrand "math/rand" "time" + + "github.com/smartcontractkit/chainlink-relay/pkg/services" ) // WithJitter adds +/- 10% to a duration @@ -27,15 +29,7 @@ func WithJitter(d time.Duration) time.Duration { // NOTE: Spins up a goroutine that exits on cancellation. // REMEMBER TO CALL CANCEL OTHERWISE IT CAN LEAD TO MEMORY LEAKS func ContextFromChan(chStop <-chan struct{}) (context.Context, context.CancelFunc) { - ctx, cancel := context.WithCancel(context.Background()) - go func() { - select { - case <-chStop: - cancel() - case <-ctx.Done(): - } - }() - return ctx, cancel + return services.StopRChan(chStop).NewCtx() } // ContextWithDeadlineFn returns a copy of the parent context with the deadline modified by deadlineFn.