Skip to content

Instantly share code, notes, and snippets.

@soyart
Created April 2, 2022 11:18
Show Gist options
  • Select an option

  • Save soyart/c379c6a32186655f3be56744410a087d to your computer and use it in GitHub Desktop.

Select an option

Save soyart/c379c6a32186655f3be56744410a087d to your computer and use it in GitHub Desktop.
Graceful shutdown in Go using context.Context and chan os.Signal
package main
import (
"context"
"errors"
"fmt"
"os"
"os/signal"
"sync"
"syscall"
"time"
)
type Looper interface {
Loop(context.Context)
}
type Client interface {
Shutdown()
}
type client struct{}
func (c *client) Shutdown() {
fmt.Println("gracefully shutdown client")
}
type looper struct {
someClient Client
}
func main() {
sigChan := make(chan os.Signal, 1)
signal.Notify(
sigChan,
syscall.SIGHUP, // kill -SIGHUP XXXX
syscall.SIGINT, // kill -SIGINT XXXX or Ctrl+c
syscall.SIGQUIT, // kill -SIGQUIT XXXX
syscall.SIGTERM, // kill -SIGTERM XXXX
)
ctx, cancel := context.WithCancel(context.Background())
var wg sync.WaitGroup
wg.Add(1)
client := &client{}
looper := &looper{
someClient: client,
}
go func() {
defer wg.Done()
if err := looper.Loop(ctx); err != nil {
fmt.Println(err.Error())
}
}()
wg.Add(1)
go func() {
defer wg.Done()
<-sigChan
cancel()
}()
wg.Wait()
}
func (l *looper) Loop(ctx context.Context) error {
return l.loopUseCase(ctx)
}
func (l *looper) loopUseCase(ctx context.Context) error {
var i int
for {
select {
case <-ctx.Done():
l.someClient.Shutdown()
return errors.New("context canceled")
default:
i++
fmt.Println(i)
}
time.Sleep(time.Second)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment