From 52e76231d919d3325be9276eb1caa7cf343c1e5c Mon Sep 17 00:00:00 2001 From: Mohammad Rajabloo Date: Tue, 8 Oct 2024 22:35:20 +0330 Subject: [PATCH] refactor waitGroup chanel in a simpler solution --- README.md | 28 ++++++++++++++++++++++++++++ waitGroup.go | 27 ++++++++++----------------- waitGroup_test.go | 42 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index cf32590..907e64f 100644 --- a/README.md +++ b/README.md @@ -207,6 +207,34 @@ if err := wg.Wait(); err != nil { // oh, something bad happened in one of routines above. } ``` +### Turn WaitGroup into a chanel +```go +import ( + "github.com/mrsoftware/errors" +) + +wg := errors.NewWaitGroup() + +wg.Do(func(ctx context.Context) error { + return callingHttpClient() +}) + +wg.Do(func(ctx context.Context) error { + return callingHttpClient() +}) + +// this wait until receive something from chanel. +var err error +select { +case err = <-errors.WaitChanel(wg): +} + +if err != nil { + // oh, something bad happened in one of the routines above. +} + +``` + for mode details, check the [documentation](https://godoc.org/github.com/mrsoftware/errors) diff --git a/waitGroup.go b/waitGroup.go index cf02bc9..fb6f43b 100644 --- a/waitGroup.go +++ b/waitGroup.go @@ -14,7 +14,6 @@ type WaitGroup struct { ctx context.Context cancel context.CancelCauseFunc cancelOnce sync.Once - wait chan struct{} } // NewWaitGroup create new WaitGroup. @@ -36,7 +35,7 @@ func NewWaitGroup(options ...WaitGroupOption) *WaitGroup { ctx, cancel := context.WithCancelCause(ops.Ctx) - return &WaitGroup{options: ops, gch: gch, ctx: ctx, cancel: cancel, wait: make(chan struct{})} + return &WaitGroup{options: ops, gch: gch, ctx: ctx, cancel: cancel} } // Context of current waitGroup. @@ -55,21 +54,6 @@ func (g *WaitGroup) Wait() (err error) { defer func() { g.Stop(err) }() - select { - case g.wait <- struct{}{}: - default: - } - - return g.errors.Err() -} - -// WaitChan is like Wait method but return chanel. -func (g *WaitGroup) WaitChan() <-chan struct{} { - return g.wait -} - -// Err of tasks. -func (g *WaitGroup) Err() error { return g.errors.Err() } @@ -175,3 +159,12 @@ func WaitGroupWithContext(ctx context.Context) WaitGroupOption { g.Ctx = ctx } } + +// WaitChanel turn WaitGroup Wait method into chanel. +func WaitChanel(wg *WaitGroup) chan error { + wait := make(chan error) + + go func() { wait <- wg.Wait() }() + + return wait +} diff --git a/waitGroup_test.go b/waitGroup_test.go index ea7f425..35a3963 100644 --- a/waitGroup_test.go +++ b/waitGroup_test.go @@ -158,6 +158,48 @@ func TestGroup(t *testing.T) { }) } +func TestWaitChanel(t *testing.T) { + t.Run("expect to turn wait into chanel and work", func(t *testing.T) { + wg := NewWaitGroup() + + wg.Do(func(ctx context.Context) error { + return nil + }) + + wg.Do(func(ctx context.Context) error { + return nil + }) + + var err error + select { + case err = <-WaitChanel(wg): + } + + assert.Nil(t, err) + }) + + t.Run("expect to turn wait into chanel and get error (one task is failed)", func(t *testing.T) { + wg := NewWaitGroup() + + internalErr := errors.New("some error") + + wg.Do(func(ctx context.Context) error { + return nil + }) + + wg.Do(func(ctx context.Context) error { + return internalErr + }) + + var err error + select { + case err = <-WaitChanel(wg): + } + + assert.Equal(t, NewMultiError(internalErr), err) + }) +} + // all below test cases are copied from sync/waitgroup_test.go and transformed to group. func testWaitGroup(t *testing.T, wg1 *WaitGroup, wg2 *WaitGroup) {