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 }