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  }