gitee.com/sy_183/go-common@v1.0.5-0.20231205030221-958cfe129b47/lifecycle/test/main.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"gitee.com/sy_183/go-common/assert"
     6  	"gitee.com/sy_183/go-common/errors"
     7  	"gitee.com/sy_183/go-common/lifecycle"
     8  	"gitee.com/sy_183/go-common/log"
     9  	"math/rand"
    10  	"os"
    11  	"os/signal"
    12  	"time"
    13  )
    14  
    15  const DefaultTimeLayout = "2006-01-02 15:04:05.999999999"
    16  
    17  var logger = assert.Must(log.Config{
    18  	Level: log.NewAtomicLevelAt(log.DebugLevel),
    19  	Encoder: log.NewConsoleEncoder(log.ConsoleEncoderConfig{
    20  		DisableCaller:     true,
    21  		DisableFunction:   true,
    22  		DisableStacktrace: true,
    23  		EncodeLevel:       log.CapitalColorLevelEncoder,
    24  		EncodeTime:        log.TimeEncoderOfLayout(DefaultTimeLayout),
    25  		EncodeDuration:    log.SecondsDurationEncoder,
    26  	}),
    27  }.Build())
    28  
    29  func init() {
    30  	rand.Seed(time.Now().UnixNano())
    31  }
    32  
    33  type TestLifecycle struct {
    34  	lifecycle.Lifecycle
    35  	name string
    36  
    37  	minInterruptedStartTime, maxInterruptedStartTime,
    38  	minNotInterruptedStartTime, maxNotInterruptedStartTime,
    39  	minStartCloseTime, maxStartCloseTime,
    40  	minRunTime, maxRunTime,
    41  	minRunCloseTime, maxRunCloseTime time.Duration
    42  
    43  	startErrorRate float64
    44  	exitErrorRate  float64
    45  }
    46  
    47  type TestLifecycleConfig struct {
    48  	MinInterruptedStartTime, MaxInterruptedStartTime,
    49  	MinNotInterruptedStartTime, MaxNotInterruptedStartTime,
    50  	MinStartCloseTime, MaxStartCloseTime,
    51  	MinRunTime, MaxRunTime,
    52  	MinRunCloseTime, MaxRunCloseTime time.Duration
    53  
    54  	StartErrorRate float64
    55  	ExitErrorRate  float64
    56  }
    57  
    58  func NewTestLifecycle(name string, config TestLifecycleConfig) *TestLifecycle {
    59  	l := &TestLifecycle{name: name}
    60  	l.Lifecycle = lifecycle.NewWithInterruptedStart(l.start)
    61  	l.Lifecycle.SetOnStarting(l.onStarting).
    62  		SetOnStarted(l.onStarted).
    63  		SetOnClose(l.onClose).
    64  		SetOnClosed(l.onClosed)
    65  	l.minInterruptedStartTime = config.MinInterruptedStartTime
    66  	l.maxInterruptedStartTime = config.MaxInterruptedStartTime
    67  	l.minNotInterruptedStartTime = config.MinNotInterruptedStartTime
    68  	l.maxNotInterruptedStartTime = config.MaxNotInterruptedStartTime
    69  	l.minStartCloseTime = config.MinStartCloseTime
    70  	l.maxStartCloseTime = config.MaxStartCloseTime
    71  	l.minRunTime = config.MinRunTime
    72  	l.maxRunTime = config.MaxRunTime
    73  	l.minRunCloseTime = config.MinRunCloseTime
    74  	l.maxRunCloseTime = config.MaxRunCloseTime
    75  	l.startErrorRate = config.StartErrorRate
    76  	l.exitErrorRate = config.ExitErrorRate
    77  	return l
    78  }
    79  
    80  func (l *TestLifecycle) randDuration(min, max time.Duration) time.Duration {
    81  	return min + time.Duration(rand.Int63n(int64(max-min)))
    82  }
    83  
    84  func (l *TestLifecycle) randBool(rate float64) bool {
    85  	return rand.Float64() < rate
    86  }
    87  
    88  func (l *TestLifecycle) start(_ lifecycle.Lifecycle, interrupter chan struct{}) (_ lifecycle.InterruptedRunFunc, err error) {
    89  	select {
    90  	case <-time.After(l.randDuration(l.minInterruptedStartTime, l.maxInterruptedStartTime)):
    91  	case <-interrupter:
    92  		time.Sleep(l.randDuration(l.minStartCloseTime, l.maxStartCloseTime))
    93  		return nil, errors.New("生命周期组件启动被中断")
    94  	}
    95  	logger.Warn("生命周期组件启动已不可被中断", log.String("组件名称", l.name))
    96  	time.Sleep(l.randDuration(l.minNotInterruptedStartTime, l.maxNotInterruptedStartTime))
    97  	if l.randBool(l.startErrorRate) {
    98  		err = errors.New("启动错误")
    99  	}
   100  	return func(lifecycle.Lifecycle, chan struct{}) (err error) {
   101  		select {
   102  		case <-time.After(l.randDuration(l.minRunTime, l.maxRunTime)):
   103  		case <-interrupter:
   104  			time.Sleep(l.randDuration(l.minRunCloseTime, l.maxRunCloseTime))
   105  			return errors.New("生命周期组件运行被中断")
   106  		}
   107  		if l.randBool(l.exitErrorRate) {
   108  			return errors.New("退出错误")
   109  		}
   110  		return nil
   111  	}, err
   112  }
   113  
   114  func (l *TestLifecycle) onStarting(lifecycle.Lifecycle) {
   115  	logger.Info("组件正在启动...", log.String("组件名称", l.name))
   116  }
   117  
   118  func (l *TestLifecycle) onStarted(_ lifecycle.Lifecycle, err error) {
   119  	if err != nil {
   120  		logger.Error("组件启动失败", log.String("组件名称", l.name), log.NamedError("错误原因", err))
   121  	} else {
   122  		logger.Info("组件启动成功", log.String("组件名称", l.name))
   123  	}
   124  }
   125  
   126  func (l *TestLifecycle) onClose(_ lifecycle.Lifecycle, err error) {
   127  	if err != nil {
   128  		logger.Error("组件关闭失败", log.String("组件名称", l.name), log.NamedError("错误原因", err))
   129  	} else {
   130  		logger.Info("组件正在关闭", log.String("组件名称", l.name))
   131  	}
   132  }
   133  
   134  func (l *TestLifecycle) onClosed(_ lifecycle.Lifecycle, err error) {
   135  	if err != nil {
   136  		logger.Error("组件退出错误", log.String("组件名称", l.name), log.NamedError("错误原因", err))
   137  	} else {
   138  		logger.Info("组件成功退出", log.String("组件名称", l.name))
   139  	}
   140  }
   141  
   142  func testGroup() {
   143  	group := lifecycle.NewGroup()
   144  	config := TestLifecycleConfig{
   145  		MinInterruptedStartTime:    time.Second,
   146  		MaxInterruptedStartTime:    time.Second * 2,
   147  		MinNotInterruptedStartTime: time.Second,
   148  		MaxNotInterruptedStartTime: time.Second * 2,
   149  		MinStartCloseTime:          time.Millisecond * 500,
   150  		MaxStartCloseTime:          time.Millisecond * 800,
   151  		MinRunTime:                 time.Second * 10,
   152  		MaxRunTime:                 time.Second * 15,
   153  		MinRunCloseTime:            time.Millisecond * 800,
   154  		MaxRunCloseTime:            time.Millisecond * 1200,
   155  		StartErrorRate:             0.1,
   156  		ExitErrorRate:              0.1,
   157  	}
   158  
   159  	for i := 0; i < 20; i++ {
   160  		name := fmt.Sprintf("test%d", i)
   161  		group.MustAdd(name, lifecycle.NewRetryable(NewTestLifecycle(name, config)).SetLazyStart(true).SetRetryInterval(time.Second))
   162  	}
   163  
   164  	exitChan := make(chan os.Signal)
   165  	signal.Notify(exitChan, os.Interrupt, os.Kill)
   166  	go func() {
   167  		<-exitChan
   168  		group.Close(nil)
   169  	}()
   170  	go func() {
   171  		for i := 20; i < 30; i++ {
   172  			name := fmt.Sprintf("test%d", i)
   173  			group.MustAdd(name, lifecycle.NewRetryable(NewTestLifecycle(name, config)).SetLazyStart(true).SetRetryInterval(time.Second))
   174  			logger.Info("组件添加成功", log.String("组件名称", name))
   175  			time.Sleep(time.Millisecond * 500)
   176  		}
   177  	}()
   178  	group.Run()
   179  }
   180  
   181  func testList() {
   182  	list := lifecycle.NewList()
   183  
   184  	for i := 0; i < 20; i++ {
   185  		name := fmt.Sprintf("test%d", i)
   186  		list.Append(NewTestLifecycle(name, TestLifecycleConfig{
   187  			MinInterruptedStartTime:    time.Millisecond * 500,
   188  			MaxInterruptedStartTime:    time.Millisecond * 800,
   189  			MinNotInterruptedStartTime: time.Millisecond * 500,
   190  			MaxNotInterruptedStartTime: time.Millisecond * 800,
   191  			MinStartCloseTime:          time.Millisecond * 200,
   192  			MaxStartCloseTime:          time.Millisecond * 500,
   193  			MinRunTime:                 time.Second * 10,
   194  			MaxRunTime:                 time.Second * 15,
   195  			MinRunCloseTime:            time.Millisecond * 500,
   196  			MaxRunCloseTime:            time.Millisecond * 800,
   197  		}))
   198  	}
   199  
   200  	exitChan := make(chan os.Signal)
   201  	signal.Notify(exitChan, os.Interrupt, os.Kill)
   202  	go func() {
   203  		<-exitChan
   204  		list.Close(nil)
   205  	}()
   206  	list.Run()
   207  }
   208  
   209  func testRetryable() {
   210  	retryable := lifecycle.NewRetryable(NewTestLifecycle("test", TestLifecycleConfig{
   211  		MinInterruptedStartTime:    time.Second,
   212  		MaxInterruptedStartTime:    time.Second * 2,
   213  		MinNotInterruptedStartTime: time.Second,
   214  		MaxNotInterruptedStartTime: time.Second * 2,
   215  		MinStartCloseTime:          time.Millisecond * 500,
   216  		MaxStartCloseTime:          time.Millisecond * 800,
   217  		MinRunTime:                 time.Second * 2,
   218  		MaxRunTime:                 time.Second * 3,
   219  		MinRunCloseTime:            time.Millisecond * 800,
   220  		MaxRunCloseTime:            time.Millisecond * 1200,
   221  		StartErrorRate:             0.5,
   222  		ExitErrorRate:              0.5,
   223  	})).SetLazyStart(true).SetRetryInterval(time.Second)
   224  	exitChan := make(chan os.Signal)
   225  	signal.Notify(exitChan, os.Interrupt, os.Kill)
   226  	go func() {
   227  		<-exitChan
   228  		retryable.Close(nil)
   229  	}()
   230  	retryable.Run()
   231  }
   232  
   233  func main() {
   234  	testGroup()
   235  	//testList()
   236  	//testRetryable()
   237  }