iface.go
package GabrielConfig import ( "context" "sync" ) type IGracefulExit interface { Cancel() GetCtx() context.Context GetWaitGroupInCtx() *sync.WaitGroup }
graceful_exit.go
package GabrielConfig import ( "context" "sync" ) var GabrielGracefulExit IGracefulExit // goroutine优雅退出使用的接口 var gabrielGracefulExitOnce sync.Once // goroutine优雅退出使用单例模式 type GracefulExit struct { ctx context.Context // ctx用于所有服务等待停止并回收资源 cancel context.CancelFunc // 函数执行将通知所有服务停止并回收资源 } const ( ctxKeyWaitGroup = "WaitGroup" ) func NewRoutineSync() IGracefulExit { if GabrielGracefulExit == nil { gabrielGracefulExitOnce.Do(func() { ctx, cancel := context.WithCancel(context.WithValue(context.Background(), ctxKeyWaitGroup, new(sync.WaitGroup))) GabrielGracefulExit = &GracefulExit{ ctx: ctx, cancel: cancel, } }) } return GabrielGracefulExit } func (g *GracefulExit) Cancel() { g.cancel() } func (g *GracefulExit) GetCtx() context.Context { return g.ctx } func (g *GracefulExit) GetWaitGroupInCtx() *sync.WaitGroup { if wg, ok := g.ctx.Value(ctxKeyWaitGroup).(*sync.WaitGroup); ok { return wg } return nil } /* 使用方式如下: func server(ge IGracefulExit) error{ defer func(){ // 提供服务 } ... ... // 初始化服务配置 ... ... ge.GetWaitGroupInCtx().Add(1) go func(){ defer ge.GetWaitGroupInCtx().Done() <-ge.GetCtx().Done() ... ... // 执行服务关闭操作 ... ... } return nil } func main(){ defer func(){ ge.Cancel() ge.GetWaitGroupInCtx().Wait() } server(ge) quit := make(chan os.Signal) // kill (no param) default send syscall.SIGTERM // kill -2 is syscall.SIGINT // kill -9 is syscall. SIGKILL but can"t be catch, so don't need add it signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit } */