package graceful import ( "context" "golang.org/x/sync/errgroup" "log" "os" "os/signal" "syscall" ) func init() { log.SetOutput(os.Stdout) } type IRunner interface { Run(ctx context.Context) error Stop() } type Graceful struct{} type Opt func(*Graceful) func New() *Graceful { return &Graceful{} } func (g *Graceful) Run(r ...IRunner) { eg := &errgroup.Group{} ctx, cancel := context.WithCancel(context.Background()) defer cancel() for _, v := range r { goRun(ctx, eg, v) } eg.Go(func() error { ch := make(chan os.Signal, 1) signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM) select { case v := <-ch: log.Printf("catch notfiy stop: %v", v) } cancel() for _, v := range r { v.Stop() } return nil }) defer func() { log.Printf("server stop") }() err := eg.Wait() if err != nil { log.Println(err) return } } func goRun(ctx context.Context, eg *errgroup.Group, r IRunner) { eg.Go(func() error { err := r.Run(ctx) if err != nil { log.Printf("run err: %s", err) return err } return nil }) }