Skip to content

Instantly share code, notes, and snippets.

@dimus
Forked from pteich/main.go
Created March 13, 2022 11:49
Show Gist options
  • Save dimus/71da799ab0e882738a8dd8973f68721f to your computer and use it in GitHub Desktop.
Save dimus/71da799ab0e882738a8dd8973f68721f to your computer and use it in GitHub Desktop.
Example for using go's sync.errgroup together with signal detection signal.Notify to stop all running goroutines
package main
import (
"context"
"errors"
"fmt"
"os"
"os/signal"
"syscall"
"time"
"golang.org/x/sync/errgroup"
)
func main() {
ctx, done := context.WithCancel(context.Background())
g, gctx := errgroup.WithContext(ctx)
// goroutine to check for signals to gracefully finish all functions
g.Go(func() error {
signalChannel := make(chan os.Signal, 1)
signal.Notify(signalChannel, os.Interrupt, syscall.SIGTERM)
select {
case sig := <-signalChannel:
fmt.Printf("Received signal: %s\n", sig)
done()
case <-gctx.Done():
fmt.Printf("closing signal goroutine\n")
return gctx.Err()
}
return nil
})
// just a ticker every 2s
g.Go(func() error {
ticker := time.NewTicker(2 * time.Second)
for {
select {
case <-ticker.C:
fmt.Printf("ticker 2s ticked\n")
// testcase what happens if an error occured
//return fmt.Errorf("test error ticker 2s")
case <-gctx.Done():
fmt.Printf("closing ticker 2s goroutine\n")
return gctx.Err()
}
}
})
// just a ticker every 1s
g.Go(func() error {
ticker := time.NewTicker(1 * time.Second)
for {
select {
case <-ticker.C:
fmt.Printf("ticker 1s ticked\n")
case <-gctx.Done():
fmt.Printf("closing ticker 1s goroutine\n")
return gctx.Err()
}
}
})
// force a stop after 60s
time.AfterFunc(60*time.Second, func() {
fmt.Printf("force finished after 60s")
done()
})
// wait for all errgroup goroutines
err := g.Wait()
if err != nil {
if errors.Is(err, context.Canceled) {
fmt.Print("context was canceled")
} else {
fmt.Printf("received error: %v", err)
}
} else {
fmt.Println("finished clean")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment