diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ae59a79..0cea268 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -9,7 +9,7 @@ jobs: steps: - uses: actions/setup-go@v3 with: - go-version: '1.19' + go-version: '1.20' - uses: actions/checkout@v3 - name: golangci-lint uses: golangci/golangci-lint-action@v3 diff --git a/README.md b/README.md index 0896c60..1d6c236 100644 --- a/README.md +++ b/README.md @@ -119,4 +119,96 @@ type Dispatcher[Task any] func(ctx context.Context) ([]Task, error) type ErrorHandler[Task any] func(ctx context.Context, err error) ``` -Also it receives 2 integers: workers count and time between dispatcher calls in milliseconds. \ No newline at end of file +Also it receives 2 integers: workers count and time between dispatcher calls in milliseconds. + +# Group + +`Group` can be used for running processes with wait group. For example: + +```go +// this program runs 2 ticker functions and waits its executed. +func main() { + group := NewGroup() + group.Go(ticker3) + group.Go(ticker4) + group.Wait() +} + +func ticker3() { + ticker := time.NewTicker(time.Second) + defer ticker.Stop() + + var count int + + for range ticker.C { + count++ + log.Print("second") + + if count == 5 { + return + } + } +} + +func ticker4() { + ticker := time.NewTicker(time.Second * 2) + defer ticker.Stop() + + var count int + + for range ticker.C { + count++ + log.Print("2 second") + + if count == 5 { + return + } + } +} +``` + +With using context: + +```go +// the program runs two tickers and after 10 seconds cancel it using context cancellation +func main() { + ctx, cancel := context.WithCancel(context.Background()) + + group := NewGroup() + group.GoCtx(ctx, ticker1) + group.GoCtx(ctx, ticker2) + + time.Sleep(10 * time.Second) + cancel() + + group.Wait() +} + +func ticker1(ctx context.Context) { + ticker := time.NewTicker(time.Second) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + return + case <-ticker.C: + log.Print("second") + } + } +} + +func ticker2(ctx context.Context) { + ticker := time.NewTicker(time.Second * 2) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + return + case <-ticker.C: + log.Print("2 second") + } + } +} +``` \ No newline at end of file diff --git a/group.go b/group.go new file mode 100644 index 0000000..4cc6f4a --- /dev/null +++ b/group.go @@ -0,0 +1,41 @@ +package workerpool + +import ( + "context" + "sync" +) + +// Runs functions with one wait group +type Group struct { + wg *sync.WaitGroup +} + +// NewGroup - creates new Group +func NewGroup() Group { + return Group{ + wg: new(sync.WaitGroup), + } +} + +// Go - runs function with wait group +func (g Group) Go(f func()) { + g.wg.Add(1) + go func() { + defer g.wg.Done() + f() + }() +} + +// GoCtx - runs function with wait group using context +func (g Group) GoCtx(ctx context.Context, f func(ctx context.Context)) { + g.wg.Add(1) + go func() { + defer g.wg.Done() + f(ctx) + }() +} + +// Wait - waits until grouped functions end +func (g Group) Wait() { + g.wg.Wait() +} diff --git a/group_test.go b/group_test.go new file mode 100644 index 0000000..1186976 --- /dev/null +++ b/group_test.go @@ -0,0 +1,88 @@ +package workerpool + +import ( + "context" + "log" + "testing" + "time" +) + +func TestGroupWithContext(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + + group := NewGroup() + group.GoCtx(ctx, ticker1) + group.GoCtx(ctx, ticker2) + + time.Sleep(10 * time.Second) + cancel() + + group.Wait() +} + +func ticker1(ctx context.Context) { + ticker := time.NewTicker(time.Second) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + return + case <-ticker.C: + log.Print("second") + } + } +} + +func ticker2(ctx context.Context) { + ticker := time.NewTicker(time.Second * 2) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + return + case <-ticker.C: + log.Print("2 second") + } + } +} + +func TestGroup(t *testing.T) { + group := NewGroup() + group.Go(ticker3) + group.Go(ticker4) + group.Wait() +} + +func ticker3() { + ticker := time.NewTicker(time.Second) + defer ticker.Stop() + + var count int + + for range ticker.C { + count++ + log.Print("second") + + if count == 5 { + return + } + } +} + +func ticker4() { + ticker := time.NewTicker(time.Second * 2) + defer ticker.Stop() + + var count int + + for range ticker.C { + count++ + log.Print("2 second") + + if count == 5 { + return + } + } +}