github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/module/common.go (about) 1 package module 2 3 import ( 4 "errors" 5 "sync" 6 7 "github.com/onflow/flow-go/module/irrecoverable" 8 ) 9 10 // WARNING: The semantics of this interface will be changing in the near future, with 11 // startup / shutdown capabilities being delegated to the Startable interface instead. 12 // For more details, see https://github.com/onflow/flow-go/pull/1167 13 // 14 // ReadyDoneAware provides an easy interface to wait for module startup and shutdown. 15 // Modules that implement this interface only support a single start-stop cycle, and 16 // will not restart if Ready() is called again after shutdown has already commenced. 17 type ReadyDoneAware interface { 18 // Ready commences startup of the module, and returns a ready channel that is closed once 19 // startup has completed. Note that the ready channel may never close if errors are 20 // encountered during startup. 21 // If shutdown has already commenced before this method is called for the first time, 22 // startup will not be performed and the returned channel will also never close. 23 // This should be an idempotent method. 24 Ready() <-chan struct{} 25 26 // Done commences shutdown of the module, and returns a done channel that is closed once 27 // shutdown has completed. Note that the done channel should be closed even if errors are 28 // encountered during shutdown. 29 // This should be an idempotent method. 30 Done() <-chan struct{} 31 } 32 33 // NoopReadyDoneAware is a ReadyDoneAware implementation whose ready/done channels close 34 // immediately 35 type NoopReadyDoneAware struct{} 36 37 func (n *NoopReadyDoneAware) Ready() <-chan struct{} { 38 ready := make(chan struct{}) 39 defer close(ready) 40 return ready 41 } 42 43 func (n *NoopReadyDoneAware) Done() <-chan struct{} { 44 done := make(chan struct{}) 45 defer close(done) 46 return done 47 } 48 49 // NoopComponent noop struct that implements the component.Component interface. 50 type NoopComponent struct { 51 *NoopReadyDoneAware 52 } 53 54 func (n *NoopComponent) Start(_ irrecoverable.SignalerContext) {} 55 56 // ProxiedReadyDoneAware is a ReadyDoneAware implementation that proxies the ReadyDoneAware interface 57 // from another implementation. This allows for usecases where the Ready/Done methods are needed before 58 // the proxied object is initialized. 59 type ProxiedReadyDoneAware struct { 60 ready chan struct{} 61 done chan struct{} 62 63 initOnce sync.Once 64 } 65 66 // NewProxiedReadyDoneAware returns a new ProxiedReadyDoneAware instance 67 func NewProxiedReadyDoneAware() *ProxiedReadyDoneAware { 68 return &ProxiedReadyDoneAware{ 69 ready: make(chan struct{}), 70 done: make(chan struct{}), 71 } 72 } 73 74 // Init adds the proxied ReadyDoneAware implementation and sets up the ready/done channels 75 // to close when the respective channel on the proxied object closes. 76 // Init can only be called once. 77 // 78 // IMPORTANT: the proxied ReadyDoneAware implementation must be idempotent since the Ready and Done 79 // methods will be called immediately when calling Init. 80 func (n *ProxiedReadyDoneAware) Init(rda ReadyDoneAware) { 81 n.initOnce.Do(func() { 82 go func() { 83 <-rda.Ready() 84 close(n.ready) 85 }() 86 go func() { 87 <-rda.Done() 88 close(n.done) 89 }() 90 }) 91 } 92 93 func (n *ProxiedReadyDoneAware) Ready() <-chan struct{} { 94 return n.ready 95 } 96 97 func (n *ProxiedReadyDoneAware) Done() <-chan struct{} { 98 return n.done 99 } 100 101 var ErrMultipleStartup = errors.New("component may only be started once") 102 103 // Startable provides an interface to start a component. Once started, the component 104 // can be stopped by cancelling the given context. 105 type Startable interface { 106 // Start starts the component. Any irrecoverable errors encountered while the component is running 107 // should be thrown with the given SignalerContext. 108 // This method should only be called once, and subsequent calls should panic with ErrMultipleStartup. 109 Start(irrecoverable.SignalerContext) 110 }