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
}
*/