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 }