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  }