github.com/sandwich-go/boost@v1.3.29/module/master.go (about) 1 package module 2 3 import ( 4 "context" 5 "fmt" 6 "github.com/sandwich-go/boost" 7 "github.com/sandwich-go/boost/version" 8 "github.com/sandwich-go/boost/xdebug" 9 "github.com/sandwich-go/boost/xdebug/race" 10 "github.com/sandwich-go/boost/xpanic" 11 "github.com/sandwich-go/boost/xsync" 12 "os" 13 "sync" 14 "time" 15 ) 16 17 type agent struct { 18 master *master 19 Module 20 wg sync.WaitGroup 21 closeChan chan struct{} 22 } 23 24 func (a *agent) run() { 25 a.master.runningCount.Add(1) 26 a.Run(a.closeChan) 27 a.wg.Done() 28 if a.master.runningCount.Add(-1) == 0 { 29 a.master.Stop(fmt.Sprintf("%s stopped, no module in running", a.Name())) 30 } 31 } 32 33 func (a *agent) close() { 34 xpanic.Do(func() { 35 a.OnClose() 36 boost.LogInfof("ModuleName %s closed", a.Name()) 37 }, func(p *xpanic.Panic) { 38 boost.LogInfof("ModuleName %s closed with reason: %v", a.Name(), p.Reason) 39 }) 40 } 41 42 // master Module管理器 43 type master struct { 44 masterStarted xsync.AtomicBool 45 timeoutDuration time.Duration 46 allAgents []*agent 47 runningCount xsync.AtomicInt32 48 chanHasShutdown chan struct{} 49 chanStoppedByLogic chan string // 逻辑导致的退出,用户主动停止,逻辑异常停止 50 plugins []Plugin 51 } 52 53 // New 新建一个 Module 管理器,一般情况下使用默认 default 即可 54 func New() *master { 55 return &master{ 56 chanHasShutdown: make(chan struct{}), 57 chanStoppedByLogic: make(chan string, 1), 58 } 59 } 60 61 func (m *master) Modules() []Module { 62 var out = make([]Module, 0, len(m.allAgents)) 63 for i := 0; i < len(m.allAgents); i++ { 64 out = append(out, m.allAgents[i].Module) 65 } 66 return out 67 } 68 69 func (m *master) AttachPlugin(plugins ...Plugin) { 70 if len(plugins) > 0 { 71 m.plugins = append(m.plugins, plugins...) 72 } 73 } 74 75 func (m *master) afterRunModule(ctx context.Context) { 76 for _, v := range m.plugins { 77 v.AfterRunModule(ctx, m) 78 } 79 } 80 81 func (m *master) beforeCloseModule(ctx context.Context) { 82 for _, v := range m.plugins { 83 v.BeforeCloseModule(ctx, m) 84 } 85 } 86 87 func (m *master) registerOneModule(md Module) *agent { 88 a := &agent{Module: md, master: m, closeChan: make(chan struct{}, 1)} 89 m.allAgents = append(m.allAgents, a) 90 return a 91 } 92 93 // Register 注册多个Module 94 func (m *master) Register(ms ...Module) { 95 for _, md := range ms { 96 _ = m.registerOneModule(md) 97 } 98 } 99 100 // Stop 主动停止Master 101 func (m *master) Stop(reason ...string) { 102 var s = "stop_called" 103 if len(reason) > 0 { 104 s = reason[0] 105 } 106 select { 107 case <-m.chanStoppedByLogic: 108 default: 109 } 110 m.chanStoppedByLogic <- s 111 } 112 113 func (m *master) runAll() { 114 for i := 0; i < len(m.allAgents); i++ { 115 m.allAgents[i].OnInit() 116 } 117 118 for i := 0; i < len(m.allAgents); i++ { 119 boost.LogInfof("ModuleName %s starting ...", m.allAgents[i].Name()) 120 m.allAgents[i].wg.Add(1) 121 go m.allAgents[i].run() 122 boost.LogInfof("ModuleName %s started ...", m.allAgents[i].Name()) 123 } 124 } 125 126 // RunModule 运行一个单独的 module 127 func (m *master) RunModule(md Module) { 128 s := m.registerOneModule(md) 129 if !m.masterStarted.Get() { 130 return 131 } 132 boost.LogInfof("ModuleName %s starting ...", s.Name()) 133 s.wg.Add(1) 134 s.OnInit() 135 go s.run() 136 boost.LogInfof("ModuleName %s started", s.Name()) 137 } 138 139 func (m *master) closeAll(ctx context.Context) { 140 for i := len(m.allAgents) - 1; i >= 0; i-- { 141 a := m.allAgents[i] 142 boost.LogInfof("ModuleName %s closing ...", a.Name()) 143 close(a.closeChan) 144 if m.timeoutDuration == 0 { 145 a.wg.Wait() 146 } else { 147 if xsync.WaitContext(&a.wg, ctx) { 148 boost.LogInfof("ModuleName %s close with timeout %v ...", a.Name(), m.timeoutDuration) 149 } 150 } 151 a.close() 152 } 153 } 154 155 // RunWithCloseTimeout 参考Run,扩充了关闭超时支持,防止逻辑层堵塞导致进程关闭失败 156 func (m *master) RunWithCloseTimeout(duration time.Duration, ms ...Module) { 157 m.timeoutDuration = duration 158 m.Run(ms...) 159 } 160 161 // ShutdownNotify master停止的通知信号 162 func (m *master) ShutdownNotify() chan struct{} { return m.chanHasShutdown } 163 164 // Run 运行入口,进程会堵塞在这里直到收到停止信号,可以指定要运行的Module列表 165 func (m *master) Run(ms ...Module) { 166 m.Register(ms...) 167 m.runAll() 168 169 xdebug.CheckRequireDependencies() 170 boost.LogInfof("progress started, pid: %d, version: %s, race: %t, debug_enabled: %t", 171 os.Getpid(), version.String(), race.Enabled, xdebug.Enabled()) 172 173 ctx := context.Background() 174 go func() { 175 m.afterRunModule(ctx) 176 }() 177 m.masterStarted.Set(true) 178 179 reason := "unknown" 180 // Block until a signal is received 181 select { 182 case reason = <-m.chanStoppedByLogic: 183 case <-ProcessShutdownNotify(): 184 reason = fmt.Sprintf("sig(%s)", processShutdownSignal.String()) 185 } 186 187 boost.LogInfof("progress closing down by signal, pid: %d, reason: %s", os.Getpid(), reason) 188 189 m.masterStarted.Set(false) 190 191 if m.timeoutDuration != 0 { 192 var cancelFunc context.CancelFunc 193 ctx, cancelFunc = context.WithDeadline(ctx, time.Now().Add(m.timeoutDuration)) 194 defer cancelFunc() 195 } 196 beforeCloseModuleDone := make(chan struct{}) 197 go func() { 198 m.beforeCloseModule(ctx) 199 close(beforeCloseModuleDone) 200 }() 201 202 select { 203 case <-beforeCloseModuleDone: 204 case <-ctx.Done(): 205 } 206 207 m.closeAll(ctx) 208 close(m.chanHasShutdown) 209 }