123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 |
- // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
- //
- // This Source Code Form is subject to the terms of the MIT License.
- // If a copy of the MIT was not distributed with this file,
- // You can obtain one at https://github.com/gogf/gf.
- package gproc
- import (
- "context"
- "os"
- "os/signal"
- "sync"
- "syscall"
- "github.com/gogf/gf/v2/internal/intlog"
- "github.com/gogf/gf/v2/util/gutil"
- )
- // SigHandler defines a function type for signal handling.
- type SigHandler func(sig os.Signal)
- var (
- // Use internal variable to guarantee concurrent safety
- // when multiple Listen happen.
- signalChan = make(chan os.Signal, 1)
- signalHandlerMu sync.Mutex
- signalHandlerMap = make(map[os.Signal][]SigHandler)
- shutdownSignalMap = map[os.Signal]struct{}{
- syscall.SIGINT: {},
- syscall.SIGQUIT: {},
- syscall.SIGKILL: {},
- syscall.SIGTERM: {},
- syscall.SIGABRT: {},
- }
- )
- func init() {
- for sig := range shutdownSignalMap {
- signalHandlerMap[sig] = make([]SigHandler, 0)
- }
- }
- // AddSigHandler adds custom signal handler for custom one or more signals.
- func AddSigHandler(handler SigHandler, signals ...os.Signal) {
- signalHandlerMu.Lock()
- defer signalHandlerMu.Unlock()
- for _, sig := range signals {
- signalHandlerMap[sig] = append(signalHandlerMap[sig], handler)
- }
- }
- // AddSigHandlerShutdown adds custom signal handler for shutdown signals:
- // syscall.SIGINT,
- // syscall.SIGQUIT,
- // syscall.SIGKILL,
- // syscall.SIGTERM,
- // syscall.SIGABRT.
- func AddSigHandlerShutdown(handler ...SigHandler) {
- signalHandlerMu.Lock()
- defer signalHandlerMu.Unlock()
- for _, h := range handler {
- for sig := range shutdownSignalMap {
- signalHandlerMap[sig] = append(signalHandlerMap[sig], h)
- }
- }
- }
- // Listen blocks and does signal listening and handling.
- func Listen() {
- var (
- signals = getHandlerSignals()
- ctx = context.Background()
- wg = sync.WaitGroup{}
- sig os.Signal
- )
- signal.Notify(signalChan, signals...)
- for {
- sig = <-signalChan
- intlog.Printf(ctx, `signal received: %s`, sig.String())
- if handlers := getHandlersBySignal(sig); len(handlers) > 0 {
- for _, handler := range handlers {
- wg.Add(1)
- var (
- currentHandler = handler
- currentSig = sig
- )
- gutil.TryCatch(ctx, func(ctx context.Context) {
- defer wg.Done()
- currentHandler(currentSig)
- }, func(ctx context.Context, exception error) {
- intlog.Errorf(ctx, `execute signal handler failed: %+v`, exception)
- })
- }
- }
- // If it is shutdown signal, it exits this signal listening.
- if _, ok := shutdownSignalMap[sig]; ok {
- intlog.Printf(
- ctx,
- `receive shutdown signal "%s", waiting all signal handler done`,
- sig.String(),
- )
- // Wait until signal handlers done.
- wg.Wait()
- intlog.Print(ctx, `all signal handler done, exit process`)
- return
- }
- }
- }
- func getHandlerSignals() []os.Signal {
- signalHandlerMu.Lock()
- defer signalHandlerMu.Unlock()
- var signals = make([]os.Signal, 0)
- for s := range signalHandlerMap {
- signals = append(signals, s)
- }
- return signals
- }
- func getHandlersBySignal(sig os.Signal) []SigHandler {
- signalHandlerMu.Lock()
- defer signalHandlerMu.Unlock()
- return signalHandlerMap[sig]
- }
|