package hook import ( "fmt" "os" "os/signal" "reflect" "sync" "syscall" "time" ) type ShutdownHook struct { hooks map[string]func(os.Signal) hooksMain func(os.Signal) mutex *sync.Mutex } var defaultHook = &ShutdownHook{ mutex: &sync.Mutex{},hooks: map[string]func(os.Signal){}} func Listen(signals ...os.Signal) { defaultHook.Listen(signals...) } func RegistryHook(name string, fn func(string)) { defaultHook.RegistryHook(name, fn) } func RegistryMainHook(fn func()) { defaultHook.RegistryMainHook(fn) } func (s *ShutdownHook) RegistryMainHook(fn func()) { s.RegistryMainHookWithParam(func(os.Signal) { fmt.Printf("[####] main shutdown process start...\n") fn() fmt.Printf("[####] main shutdown process end...\n") }) } func (s *ShutdownHook) RegistryHook(name string, fn func(string)) { s.RegistryHookWithParam(name, func(os.Signal) { fmt.Printf("[####] %v shutdown process start...\n", name) fn(name) fmt.Printf("[####] %v shutdown process end...\n", name) }) } func (s *ShutdownHook) RegistryHookWithParam(name string, fn func(os.Signal)) { s.mutex.Lock() defer s.mutex.Unlock() s.hooks[name] = fn } func (s *ShutdownHook) RegistryMainHookWithParam( fn func(os.Signal)) { s.hooksMain = fn } func (s *ShutdownHook) Hooks() map[string]func(os.Signal) { s.mutex.Lock() defer s.mutex.Unlock() fns := map[string]func(os.Signal){} for k, v := range s.hooks { fns[k] = v } return fns } func (s *ShutdownHook) Listen(signals ...os.Signal) { ch := make(chan os.Signal, 1) var ( sig os.Signal timeGap int64 ) for { signal.Notify(ch, signals...) sig = <-ch target := reflect.ValueOf(sig) fmt.Println("[######] Enter End Signal... [", target.String(),"]","[", sig.String(),"]") if sig == syscall.SIGINT { timeNow := time.Now().UnixNano() if timeNow < timeGap+(1000*int64(time.Millisecond)) { break } timeGap = time.Now().UnixNano() } else if sig == syscall.SIGTERM || sig == syscall.SIGKILL || sig == syscall.SIGQUIT { // Delete syscall.SIGHUP break } } fmt.Println("[######] shutdown process start... ", sig.String()) // SUB HOOK PROCESS var wg sync.WaitGroup for _, fn := range s.Hooks() { wg.Add(1) go func(sig os.Signal, fn func(os.Signal)) { defer wg.Done() fn(sig) }(sig, fn) } wg.Wait() // MAIN HOOK PROCESS if s.hooksMain != nil { wg.Add(1) go func(sig os.Signal, fn func(os.Signal)) { defer wg.Done() fn(sig) }(sig, s.hooksMain) } wg.Wait() fmt.Println("[######] shutdown process complete...") }