github.com/xmidt-org/webpa-common@v1.11.9/concurrent/runnable.go (about)

     1  package concurrent
     2  
     3  import (
     4  	"os"
     5  	"sync"
     6  )
     7  
     8  // Runnable represents any operation that can spawn zero or more goroutines.
     9  type Runnable interface {
    10  	// Run executes this operation, possibly returning an error if the operation
    11  	// could not be started.  This method is responsible for spawning any necessary
    12  	// goroutines and to ensure WaitGroup.Add() and WaitGroup.Done() are called appropriately.
    13  	// Generally speaking, Run() should be idempotent.
    14  	//
    15  	// The supplied shutdown channel is used to signal any goroutines spawned by this
    16  	// method that they should gracefully exit.  Callers can then use the waitGroup to
    17  	// wait until things have been cleaned up properly.
    18  	Run(waitGroup *sync.WaitGroup, shutdown <-chan struct{}) error
    19  }
    20  
    21  // RunnableFunc is a function type that implements Runnable
    22  type RunnableFunc func(*sync.WaitGroup, <-chan struct{}) error
    23  
    24  func (r RunnableFunc) Run(waitGroup *sync.WaitGroup, shutdown <-chan struct{}) error {
    25  	return r(waitGroup, shutdown)
    26  }
    27  
    28  // RunnableSet is a slice type that allows grouping of operations.
    29  // This type implements Runnable as well.
    30  type RunnableSet []Runnable
    31  
    32  func (set RunnableSet) Run(waitGroup *sync.WaitGroup, shutdown <-chan struct{}) error {
    33  	for _, operation := range set {
    34  		if err := operation.Run(waitGroup, shutdown); err != nil {
    35  			return err
    36  		}
    37  	}
    38  
    39  	return nil
    40  }
    41  
    42  // Execute is a convenience function that creates the necessary synchronization objects
    43  // and then invokes Run().
    44  func Execute(runnable Runnable) (waitGroup *sync.WaitGroup, shutdown chan struct{}, err error) {
    45  	waitGroup = &sync.WaitGroup{}
    46  	shutdown = make(chan struct{})
    47  	err = runnable.Run(waitGroup, shutdown)
    48  	return
    49  }
    50  
    51  // Await uses Execute() to invoke a runnable, then waits for any traffic
    52  // on a signal channel before shutting down gracefully.
    53  func Await(runnable Runnable, signals <-chan os.Signal) error {
    54  	waitGroup, shutdown, err := Execute(runnable)
    55  	if err != nil {
    56  		return err
    57  	}
    58  
    59  	<-signals
    60  
    61  	close(shutdown)
    62  	waitGroup.Wait()
    63  	return nil
    64  }