gitee.com/sy_183/go-common@v1.0.5-0.20231205030221-958cfe129b47/lifecycle/list.go (about) 1 package lifecycle 2 3 import ( 4 "gitee.com/sy_183/go-common/assert" 5 "gitee.com/sy_183/go-common/lock" 6 "sync" 7 "sync/atomic" 8 ) 9 10 const ListFieldName = "$list" 11 12 type ListLifecycleHolder struct { 13 Lifecycle 14 index int 15 list *List 16 17 closeAllOnStartError atomic.Bool 18 closeAllOnExit atomic.Bool 19 closeAllOnExitError atomic.Bool 20 stopStartOnStartError atomic.Bool 21 closeBackOnExit atomic.Bool 22 closeBackOnExitError atomic.Bool 23 } 24 25 func (h *ListLifecycleHolder) List() *List { 26 return h.list 27 } 28 29 func (h *ListLifecycleHolder) SetCloseAllOnStartError(enable bool) *ListLifecycleHolder { 30 h.closeAllOnStartError.Store(enable) 31 return h 32 } 33 34 func (h *ListLifecycleHolder) SetCloseAllOnExit(enable bool) *ListLifecycleHolder { 35 h.closeAllOnExit.Store(enable) 36 return h 37 } 38 39 func (h *ListLifecycleHolder) SetCloseAllOnExitError(enable bool) *ListLifecycleHolder { 40 h.closeAllOnExitError.Store(enable) 41 return h 42 } 43 44 func (h *ListLifecycleHolder) SetStopStartOnStartError(enable bool) *ListLifecycleHolder { 45 h.stopStartOnStartError.Store(enable) 46 return h 47 } 48 49 func (h *ListLifecycleHolder) SetCloseBackOnExit(enable bool) *ListLifecycleHolder { 50 h.closeBackOnExit.Store(enable) 51 return h 52 } 53 54 func (h *ListLifecycleHolder) SetCloseBackOnExitError(enable bool) *ListLifecycleHolder { 55 h.closeBackOnExitError.Store(enable) 56 return h 57 } 58 59 type ( 60 listLifecycleContext = childLifecycleContext[*ListLifecycleHolder] 61 listLifecycleChannel = childLifecycleChannel[*ListLifecycleHolder] 62 ) 63 64 type List struct { 65 Lifecycle 66 lifecycle *DefaultLifecycle 67 68 children []*ListLifecycleHolder 69 childrenLock sync.Mutex 70 started int 71 72 closedChannel *listLifecycleChannel 73 } 74 75 func NewList() *List { 76 l := &List{ 77 closedChannel: newChildLifecycleChannel[*ListLifecycleHolder](), 78 } 79 l.lifecycle = NewWithInterruptedStart(l.start) 80 l.Lifecycle = l.lifecycle 81 return l 82 } 83 84 func (l *List) Append(lifecycle Lifecycle) (*ListLifecycleHolder, error) { 85 return lock.RLockGetDouble(l.lifecycle, func() (*ListLifecycleHolder, error) { 86 if !l.lifecycle.Closed() { 87 return nil, NewStateNotClosedError("") 88 } 89 child := &ListLifecycleHolder{ 90 Lifecycle: lifecycle, 91 index: len(l.children), 92 list: l, 93 } 94 child.SetCloseAllOnStartError(true) 95 child.SetCloseAllOnExit(true) 96 child.SetCloseAllOnExitError(true) 97 child.SetStopStartOnStartError(true) 98 child.SetCloseBackOnExit(true) 99 child.SetCloseBackOnExitError(true) 100 child.SetField(ListFieldName, l) 101 l.children = append(l.children, child) 102 return child, nil 103 }) 104 } 105 106 func (l *List) MustAppend(lifecycle Lifecycle) *ListLifecycleHolder { 107 return assert.Must(l.Append(lifecycle)) 108 } 109 110 func (l *List) shutdownChildren(children []*ListLifecycleHolder, exclude map[*ListLifecycleHolder]struct{}) { 111 excluded := func(child *ListLifecycleHolder) bool { 112 if exclude != nil { 113 _, has := exclude[child] 114 return has 115 } 116 return false 117 } 118 for i := len(children) - 1; i >= 0; i-- { 119 if !excluded(children[i]) { 120 future := make(ChanFuture[error], 1) 121 children[i].Close(future) 122 <-future 123 } 124 } 125 } 126 127 func (l *List) handleClosedSignal() (closeAll bool) { 128 closeBackIndex := -1 129 contexts := l.closedChannel.Pop() 130 var closedSet map[*ListLifecycleHolder]struct{} 131 for _, ctx := range contexts { 132 child := ctx.Lifecycle 133 if ctx.err != nil { 134 if child.closeAllOnExit.Load() || child.closeAllOnExitError.Load() { 135 closeAll = true 136 } else if child.closeBackOnExit.Load() || child.closeBackOnExitError.Load() { 137 if child.index < 0 || child.index < closeBackIndex { 138 closeBackIndex = child.index 139 } 140 } 141 } else { 142 if child.closeAllOnExit.Load() { 143 closeAll = true 144 } else if child.closeBackOnExit.Load() { 145 if child.index < 0 || child.index < closeBackIndex { 146 closeBackIndex = child.index 147 } 148 } 149 } 150 if closedSet == nil { 151 closedSet = make(map[*ListLifecycleHolder]struct{}) 152 } 153 closedSet[child] = struct{}{} 154 } 155 if closeBackIndex >= 0 { 156 l.shutdownChildren(l.children[closeBackIndex+1:l.started], closedSet) 157 } else if closeAll { 158 l.shutdownChildren(l.children[:l.started], closedSet) 159 } 160 return 161 } 162 163 func (l *List) start(_ Lifecycle, interrupter chan struct{}) (runFn InterruptedRunFunc, err error) { 164 defer func() { 165 if err != nil { 166 l.reset() 167 } 168 }() 169 170 next: 171 for i, child := range l.children { 172 future := make(ChanFuture[error], 1) 173 child.AddStartedFuture(future) 174 child.Background() 175 l.started = i + 1 176 for { 177 select { 178 case err := <-future: 179 if err != nil { 180 if child.closeAllOnStartError.Load() { 181 l.shutdownChildren(l.children[:l.started], nil) 182 return nil, NewInterruptedError("生命周期列表", "启动") 183 } else if child.stopStartOnStartError.Load() { 184 return l.run, nil 185 } 186 } else { 187 child.AddClosedFuture(listLifecycleContext{ 188 Lifecycle: child, 189 channel: l.closedChannel, 190 }) 191 } 192 continue next 193 case <-l.closedChannel.Signal(): 194 if l.handleClosedSignal() { 195 return nil, NewInterruptedError("生命周期列表", "启动") 196 } 197 case <-interrupter: 198 l.shutdownChildren(l.children[:l.started], nil) 199 return nil, NewInterruptedError("生命周期列表", "启动") 200 } 201 } 202 } 203 return l.run, nil 204 } 205 206 func (l *List) run(_ Lifecycle, interrupter chan struct{}) error { 207 defer l.reset() 208 for { 209 select { 210 case <-l.closedChannel.Signal(): 211 if l.handleClosedSignal() { 212 return nil 213 } 214 case <-interrupter: 215 l.shutdownChildren(l.children, nil) 216 return nil 217 } 218 } 219 } 220 221 func (l *List) reset() { 222 l.started = 0 223 l.closedChannel = newChildLifecycleChannel[*ListLifecycleHolder]() 224 }