gitee.com/sy_183/go-common@v1.0.5-0.20231205030221-958cfe129b47/lifecycle/group.go (about) 1 package lifecycle 2 3 import ( 4 "gitee.com/sy_183/go-common/assert" 5 "gitee.com/sy_183/go-common/errors" 6 "gitee.com/sy_183/go-common/lock" 7 "sync" 8 "sync/atomic" 9 ) 10 11 const GroupFieldName = "$group" 12 13 type GroupLifecycleHolder struct { 14 Lifecycle 15 name string 16 group *Group 17 18 removed atomic.Bool 19 20 closeAllOnStartError atomic.Bool 21 closeAllOnExit atomic.Bool 22 closeAllOnExitError atomic.Bool 23 } 24 25 func (h *GroupLifecycleHolder) Name() string { 26 return h.name 27 } 28 29 func (h *GroupLifecycleHolder) Group() *Group { 30 return h.group 31 } 32 33 func (h *GroupLifecycleHolder) SetCloseAllOnStartError(enable bool) *GroupLifecycleHolder { 34 h.closeAllOnStartError.Store(enable) 35 return h 36 } 37 38 func (h *GroupLifecycleHolder) SetCloseAllOnExit(enable bool) *GroupLifecycleHolder { 39 h.closeAllOnExit.Store(enable) 40 return h 41 } 42 43 func (h *GroupLifecycleHolder) SetCloseAllOnExitError(enable bool) *GroupLifecycleHolder { 44 h.closeAllOnExitError.Store(enable) 45 return h 46 } 47 48 type ( 49 groupLifecycleContext = childLifecycleContext[*GroupLifecycleHolder] 50 groupLifecycleChannel = childLifecycleChannel[*GroupLifecycleHolder] 51 ) 52 53 type Group struct { 54 Lifecycle 55 lifecycle *DefaultLifecycle 56 57 children map[string]*GroupLifecycleHolder 58 childrenLock sync.Mutex 59 loaded bool 60 61 runningChannel *groupLifecycleChannel 62 closedChannel *groupLifecycleChannel 63 } 64 65 func NewGroup() *Group { 66 g := &Group{ 67 children: make(map[string]*GroupLifecycleHolder), 68 runningChannel: newChildLifecycleChannel[*GroupLifecycleHolder](), 69 closedChannel: newChildLifecycleChannel[*GroupLifecycleHolder](), 70 } 71 g.lifecycle = NewWithInterruptedStart(g.start) 72 g.Lifecycle = g.lifecycle 73 return g 74 } 75 76 func (g *Group) Add(name string, lifecycle Lifecycle) (*GroupLifecycleHolder, error) { 77 return lock.RLockGetDouble(g.lifecycle, func() (*GroupLifecycleHolder, error) { 78 var loaded bool 79 child, err := lock.LockGetDouble(&g.childrenLock, func() (*GroupLifecycleHolder, error) { 80 if _, has := g.children[name]; has { 81 return nil, errors.New("生命周期组件已经存在") 82 } 83 loaded = g.loaded 84 child := &GroupLifecycleHolder{ 85 Lifecycle: lifecycle, 86 name: name, 87 group: g, 88 } 89 child.SetCloseAllOnStartError(true) 90 child.SetCloseAllOnExit(true) 91 child.SetCloseAllOnExitError(true) 92 child.SetField(GroupFieldName, g) 93 g.children[name] = child 94 return child, nil 95 }) 96 if err != nil { 97 return nil, err 98 } 99 if loaded && !g.lifecycle.Closing() { 100 child.AddStartedFuture(groupLifecycleContext{ 101 Lifecycle: child, 102 channel: g.runningChannel, 103 }) 104 child.Background() 105 } 106 return child, nil 107 }) 108 } 109 110 func (g *Group) Remove(name string) *GroupLifecycleHolder { 111 return lock.RLockGet(g.lifecycle, func() *GroupLifecycleHolder { 112 child := lock.LockGet(&g.childrenLock, func() *GroupLifecycleHolder { 113 child := g.children[name] 114 if child == nil { 115 return nil 116 } 117 child.removed.Store(true) 118 child.RemoveField(GroupFieldName) 119 delete(g.children, name) 120 return child 121 }) 122 if child == nil { 123 return nil 124 } 125 if !g.lifecycle.Closed() { 126 child.Close(nil) 127 } 128 return child 129 }) 130 } 131 132 func (g *Group) MustAdd(name string, lifecycle Lifecycle) *GroupLifecycleHolder { 133 return assert.Must(g.Add(name, lifecycle)) 134 } 135 136 func (g *Group) getChildren(setLoaded bool) []*GroupLifecycleHolder { 137 return lock.LockGet(&g.childrenLock, func() (children []*GroupLifecycleHolder) { 138 for _, child := range g.children { 139 children = append(children, child) 140 } 141 if setLoaded { 142 g.loaded = true 143 } 144 return 145 }) 146 } 147 148 func (g *Group) shutdownChildren(exclude map[*GroupLifecycleHolder]struct{}) { 149 // 此函数必需在状态为Closing的情况下执行 150 excluded := func(child *GroupLifecycleHolder) bool { 151 if exclude != nil { 152 _, has := exclude[child] 153 return has 154 } 155 return false 156 } 157 children := g.getChildren(false) 158 futures := make([]ChanFuture[error], 0) 159 for _, child := range children { 160 if !excluded(child) && !child.removed.Load() { 161 future := make(ChanFuture[error], 1) 162 child.Close(future) 163 futures = append(futures, future) 164 } 165 } 166 for _, future := range futures { 167 <-future 168 } 169 } 170 171 func (g *Group) handleRunningSignal(handleContext func(ctx groupLifecycleContext)) (closeAll bool) { 172 contexts := g.runningChannel.Pop() 173 var closedSet map[*GroupLifecycleHolder]struct{} 174 for _, ctx := range contexts { 175 child := ctx.Lifecycle 176 if handleContext != nil { 177 handleContext(ctx) 178 } 179 if child.removed.Load() { 180 continue 181 } 182 if ctx.err != nil { 183 if child.closeAllOnStartError.Load() { 184 closeAll = true 185 } 186 if closedSet == nil { 187 closedSet = make(map[*GroupLifecycleHolder]struct{}) 188 } 189 closedSet[child] = struct{}{} 190 } else { 191 child.AddClosedFuture(groupLifecycleContext{ 192 Lifecycle: child, 193 channel: g.closedChannel, 194 }) 195 } 196 } 197 if closeAll { 198 lock.LockDo(g.lifecycle, func() { g.lifecycle.ToClosing() }) 199 g.shutdownChildren(closedSet) 200 return true 201 } 202 return false 203 } 204 205 func (g *Group) handleClosedSignal(handleContext func(ctx groupLifecycleContext)) (closeAll bool) { 206 contexts := g.closedChannel.Pop() 207 var closedSet map[*GroupLifecycleHolder]struct{} 208 for _, ctx := range contexts { 209 child := ctx.Lifecycle 210 if handleContext != nil { 211 handleContext(ctx) 212 } 213 if child.removed.Load() { 214 continue 215 } 216 if ctx.err != nil { 217 if child.closeAllOnExit.Load() || child.closeAllOnExitError.Load() { 218 closeAll = true 219 } 220 } else { 221 if child.closeAllOnExit.Load() { 222 closeAll = true 223 } 224 } 225 if closedSet == nil { 226 closedSet = make(map[*GroupLifecycleHolder]struct{}) 227 } 228 closedSet[child] = struct{}{} 229 } 230 if closeAll { 231 lock.LockDo(g.lifecycle, func() { g.lifecycle.ToClosing() }) 232 g.shutdownChildren(closedSet) 233 return true 234 } 235 return false 236 } 237 238 func (g *Group) start(_ Lifecycle, interrupter chan struct{}) (runFn InterruptedRunFunc, err error) { 239 defer func() { 240 if err != nil { 241 g.reset() 242 } 243 }() 244 children := g.getChildren(true) 245 for _, child := range children { 246 child.AddStartedFuture(groupLifecycleContext{ 247 Lifecycle: child, 248 channel: g.runningChannel, 249 }) 250 child.Background() 251 } 252 childSet := make(map[*GroupLifecycleHolder]struct{}) 253 for _, child := range children { 254 childSet[child] = struct{}{} 255 } 256 startedSet := make(map[*GroupLifecycleHolder]struct{}) 257 childStarted := func(child *GroupLifecycleHolder) { 258 if _, in := childSet[child]; in { 259 startedSet[child] = struct{}{} 260 } 261 } 262 allStarted := func() bool { return len(startedSet) == len(childSet) } 263 264 for { 265 select { 266 case <-g.runningChannel.Signal(): 267 if g.handleRunningSignal(func(ctx groupLifecycleContext) { 268 if child := ctx.Lifecycle; ctx.err == nil || !child.closeAllOnStartError.Load() || child.removed.Load() { 269 childStarted(child) 270 } 271 }) { 272 return nil, NewInterruptedError("生命周期组", "启动") 273 } 274 if allStarted() { 275 return g.run, nil 276 } 277 case <-g.closedChannel.Signal(): 278 if g.handleClosedSignal(nil) { 279 return nil, NewInterruptedError("生命周期组", "启动") 280 } 281 case <-interrupter: 282 g.shutdownChildren(nil) 283 return nil, NewInterruptedError("生命周期组", "启动") 284 } 285 } 286 } 287 288 func (g *Group) run(_ Lifecycle, interrupter chan struct{}) error { 289 defer g.reset() 290 for { 291 select { 292 case <-g.runningChannel.Signal(): 293 if g.handleRunningSignal(nil) { 294 return nil 295 } 296 case <-g.closedChannel.Signal(): 297 if g.handleClosedSignal(nil) { 298 return nil 299 } 300 case <-interrupter: 301 g.shutdownChildren(nil) 302 return nil 303 } 304 } 305 } 306 307 func (g *Group) reset() { 308 lock.LockDo(&g.childrenLock, func() { g.loaded = false }) 309 g.runningChannel = newChildLifecycleChannel[*GroupLifecycleHolder]() 310 g.closedChannel = newChildLifecycleChannel[*GroupLifecycleHolder]() 311 }