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  }