-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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