github.com/iotexproject/iotex-core@v1.14.1-rc1/pkg/lifecycle/lifecycle.go (about) 1 // Copyright (c) 2018 IoTeX 2 // This source code is provided ‘as is’ and no warranties are given as to title or non-infringement, merchantability 3 // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. 4 // This source code is governed by Apache License 2.0 that can be found in the LICENSE file. 5 6 // Package lifecycle provides application models' lifecycle management. 7 package lifecycle 8 9 import ( 10 "context" 11 12 "golang.org/x/sync/errgroup" 13 ) 14 15 // Model is application model which may require to start and stop in application lifecycle. 16 type Model interface{} 17 18 // Starter is Model has a Start method. 19 type Starter interface { 20 // Start runs on lifecycle start phase. 21 Start(context.Context) error 22 } 23 24 // Stopper is Model has a Stop method. 25 type Stopper interface { 26 // Stop runs on lifecycle stop phase. 27 Stop(context.Context) error 28 } 29 30 // StartStopper is the interface that groups Start and Stop. 31 type StartStopper interface { 32 Starter 33 Stopper 34 } 35 36 // Lifecycle manages lifecycle for models. Currently a Lifecycle has two phases: Start and Stop. 37 // Currently Lifecycle doesn't support soft dependency models and multi-err, so all models in Lifecycle require to be 38 // succeed on both phases. 39 type Lifecycle struct { 40 models []Model 41 } 42 43 // Add adds a model into LifeCycle. 44 func (lc *Lifecycle) Add(m Model) { lc.models = append(lc.models, m) } 45 46 // AddModels adds multiple models into LifeCycle. 47 func (lc *Lifecycle) AddModels(m ...Model) { lc.models = append(lc.models, m...) } 48 49 // OnStart runs models OnStart function if models implmented it. All OnStart functions will be run in parallel. 50 // context passed into models' OnStart method will be canceled on the first time a model's OnStart function return non-nil error. 51 func (lc *Lifecycle) OnStart(ctx context.Context) error { 52 g, ctx := errgroup.WithContext(ctx) 53 for _, m := range lc.models { 54 if starter, ok := m.(Starter); ok { 55 g.Go(func() error { return starter.Start(ctx) }) 56 } 57 } 58 return g.Wait() 59 } 60 61 // OnStop runs models Stop function if models implmented it. All OnStop functions will be run in parallel. 62 // context passed into models' OnStop method will be canceled on the first time a model's OnStop function return non-nil error. 63 func (lc *Lifecycle) OnStop(ctx context.Context) error { 64 g, ctx := errgroup.WithContext(ctx) 65 for _, m := range lc.models { 66 if stopper, ok := m.(Stopper); ok { 67 g.Go(func() error { return stopper.Stop(ctx) }) 68 } 69 } 70 return g.Wait() 71 } 72 73 // OnStartSequentially runs models' Start function if models implmented it. 74 func (lc *Lifecycle) OnStartSequentially(ctx context.Context) error { 75 for _, m := range lc.models { 76 if starter, ok := m.(Starter); ok { 77 if err := starter.Start(ctx); err != nil { 78 return err 79 } 80 } 81 } 82 return nil 83 } 84 85 // OnStopSequentially runs models' Stop function if models implmented it. 86 func (lc *Lifecycle) OnStopSequentially(ctx context.Context) error { 87 for i := len(lc.models) - 1; i >= 0; i-- { 88 if stopper, ok := lc.models[i].(Stopper); ok { 89 if err := stopper.Stop(ctx); err != nil { 90 return err 91 } 92 } 93 } 94 return nil 95 }