github.com/influx6/npkg@v0.8.8/ndaemon/signal.go (about) 1 package ndaemon 2 3 import ( 4 "context" 5 "os" 6 "os/signal" 7 "sync" 8 "syscall" 9 10 "golang.org/x/sync/errgroup" 11 ) 12 13 func WaitForKill() os.Signal { 14 var c = WaitForKillChan() 15 return <-c 16 } 17 18 func WaitForKillChan() chan os.Signal { 19 interrupt := make(chan os.Signal, 1) 20 signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM, os.Kill) 21 return interrupt 22 } 23 24 func ContextFromKillSignal() context.Context { 25 return ContextFromKillSignalWithCtx(context.Background()) 26 } 27 28 func ContextFromKillSignalWithCtx(rootCtx context.Context) context.Context { 29 var ctx, canceler = context.WithCancel(rootCtx) 30 WaiterForKillWithSignal(WaitForKillChan(), canceler) 31 return ctx 32 } 33 34 // LaunchSignalWaitGoRoutine will lunch a groutine where it waits on a response on the signal channel 35 // at which point it calls the context cancel function. 36 func LaunchSignalWaitGoRoutine(signalChan chan os.Signal, canceler context.CancelFunc) { 37 go func() { 38 defer canceler() 39 <-signalChan 40 }() 41 } 42 43 // WaiterForKillWithSignal will call the canceler function when a interrupt/kill signal is received. 44 func WaiterForKillWithSignal(signalChan chan os.Signal, canceler context.CancelFunc) *sync.WaitGroup { 45 var waiter sync.WaitGroup 46 waiter.Add(1) 47 go func() { 48 defer waiter.Done() 49 <-signalChan 50 canceler() 51 }() 52 return &waiter 53 } 54 55 // ErrorGroupForWithSignal will call the canceler function when a interrupt/kill signal is received. 56 func ErrorGroupForWithSignal(signalChan chan os.Signal, ctx context.Context) (*errgroup.Group, context.Context) { 57 var localCtx, localCancel = context.WithCancel(ctx) 58 var group, groupContext = errgroup.WithContext(localCtx) 59 group.Go(func() error { 60 <-signalChan 61 localCancel() 62 return nil 63 }) 64 return group, groupContext 65 } 66 67 // ErrGroupForCtxSignal returns a new sync.WaitGroup which will be completed 68 // once either the context gets closed due to another goroutine closing the 69 // cancel function or the signal from the os to kill the operation. 70 func ErrGroupForCtxSignal(ctx context.Context, canceler context.CancelFunc) (*errgroup.Group, context.Context) { 71 var signalChan = WaitForKillChan() 72 var group, groupContext = errgroup.WithContext(ctx) 73 go func() { 74 defer canceler() 75 select { 76 case <-ctx.Done(): 77 break 78 case <-signalChan: 79 break 80 } 81 }() 82 return group, groupContext 83 } 84 85 // WaiterForCtxSignal returns a new sync.WaitGroup which will be completed 86 // once either the context gets closed due to another goroutine closing the 87 // cancel function or the signal from the os to kill the operation. 88 func WaiterForCtxSignal(ctx context.Context, canceler context.CancelFunc) *sync.WaitGroup { 89 var signalChan = WaitForKillChan() 90 var waiter sync.WaitGroup 91 waiter.Add(1) 92 go func() { 93 defer waiter.Done() 94 defer canceler() 95 select { 96 case <-ctx.Done(): 97 break 98 case <-signalChan: 99 break 100 } 101 }() 102 return &waiter 103 } 104 105 // CtxAndWaiterForSignal returns a new context.Context and WaitGroup which can be 106 // depended on to be closed once the os kill/interrupt signal is received. 107 func CtxAndWaiterForSignal(ctx context.Context, signalChan chan os.Signal) (*errgroup.Group, context.Context) { 108 var newCtx, canceler = context.WithCancel(ctx) 109 return SignalWithContext(signalChan, newCtx, canceler) 110 } 111 112 // WaiterForCtxSignal returns a new sync.WaitGroup which will be completed 113 // once either the context gets closed due to another goroutine closing the 114 // cancel function or the signal from the os to kill the operation. 115 func SignalWithContext(signalChan chan os.Signal, ctx context.Context, canceler context.CancelFunc) (*errgroup.Group, context.Context) { 116 var group, groupContext = errgroup.WithContext(ctx) 117 go func() { 118 defer canceler() 119 select { 120 case <-ctx.Done(): 121 break 122 case <-signalChan: 123 break 124 } 125 }() 126 return group, groupContext 127 } 128 129 // CtxAndWaiterForSignal returns a new context.Context and WaitGroup which can be 130 // depended on to be closed once the os kill/interrupt signal is received. 131 func CtxAndErrGroupForSignal(ctx context.Context, signalChan chan os.Signal) (*errgroup.Group, context.Context) { 132 var newCtx, canceler = context.WithCancel(ctx) 133 return SignalWithContext(signalChan, newCtx, canceler) 134 } 135 136 // CtxAndWaiterFor returns a new context.Context and WaitGroup which can be 137 // depended on to be closed once the os kill/interrupt signal is received. 138 func CtxAndWaiterFor(ctx context.Context) (context.Context, *sync.WaitGroup) { 139 var newCtx, canceler = context.WithCancel(ctx) 140 var signalChan = WaitForKillChan() 141 var waiter = WaiterForKillWithSignal(signalChan, canceler) 142 return newCtx, waiter 143 }