github.com/songzhibin97/gkit@v1.2.13/egroup/liftcycle.go (about)

     1  package egroup
     2  
     3  import (
     4  	"context"
     5  	"os"
     6  	"os/signal"
     7  	"syscall"
     8  
     9  	"github.com/songzhibin97/gkit/goroutine"
    10  	"github.com/songzhibin97/gkit/options"
    11  )
    12  
    13  // LifeAdminer 生命周期管理接口
    14  type LifeAdminer interface {
    15  	Start(ctx context.Context) error
    16  	Shutdown(ctx context.Context) error
    17  }
    18  
    19  // Member 成员
    20  type Member struct {
    21  	Start    func(ctx context.Context) error
    22  	Shutdown func(ctx context.Context) error
    23  }
    24  
    25  // LifeAdmin 生命周期管理
    26  type LifeAdmin struct {
    27  	opts     *config
    28  	members  []Member
    29  	shutdown func()
    30  }
    31  
    32  // Add 添加成员表(通过内部 Member 对象添加)
    33  func (l *LifeAdmin) Add(member Member) {
    34  	l.members = append(l.members, member)
    35  }
    36  
    37  // AddMember 添加程序表(通过外部接口 LifeAdminer 添加)
    38  func (l *LifeAdmin) AddMember(la LifeAdminer) {
    39  	l.members = append(l.members, Member{
    40  		Start:    la.Start,
    41  		Shutdown: la.Shutdown,
    42  	})
    43  }
    44  
    45  // Start 启动
    46  func (l *LifeAdmin) Start() error {
    47  	ctx := context.Background()
    48  	ctx, l.shutdown = context.WithCancel(ctx)
    49  	g := WithContext(ctx)
    50  	for _, m := range l.members {
    51  		func(m Member) {
    52  			// 如果有shutdown进行注册
    53  			if m.Shutdown != nil {
    54  				g.Go(func() error {
    55  					// 等待异常或信号关闭触发
    56  					<-g.ctx.Done()
    57  					return goroutine.Delegate(g.ctx, l.opts.stopTimeout, m.Shutdown)
    58  				})
    59  			}
    60  			if m.Start != nil {
    61  				g.Go(func() error {
    62  					return goroutine.Delegate(g.ctx, l.opts.startTimeout, m.Start)
    63  				})
    64  			}
    65  		}(m)
    66  	}
    67  	// 判断是否需要监听信号
    68  	if len(l.opts.signals) == 0 || l.opts.handler == nil {
    69  		return g.Wait()
    70  	}
    71  	c := make(chan os.Signal, len(l.opts.signals))
    72  	// 监听信号
    73  	signal.Notify(c, l.opts.signals...)
    74  	g.Go(func() error {
    75  		for {
    76  			select {
    77  			case <-g.ctx.Done():
    78  				return g.ctx.Err()
    79  			case sig := <-c:
    80  				l.opts.handler(l, sig)
    81  			}
    82  		}
    83  	})
    84  	return g.Wait()
    85  }
    86  
    87  // Shutdown 停止服务
    88  func (l *LifeAdmin) Shutdown() {
    89  	if l.shutdown != nil {
    90  		l.shutdown()
    91  	}
    92  }
    93  
    94  // NewLifeAdmin 实例化方法
    95  func NewLifeAdmin(opts ...options.Option) *LifeAdmin {
    96  	// 默认参数
    97  	o := &config{
    98  		startTimeout: startTimeout,
    99  		stopTimeout:  stopTimeout,
   100  		signals:      []os.Signal{syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGINT},
   101  		handler: func(a *LifeAdmin, signal os.Signal) {
   102  			switch signal {
   103  			case syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGINT:
   104  				a.Shutdown()
   105  			default:
   106  			}
   107  		},
   108  	}
   109  	// 选项模式填充参数
   110  	for _, opt := range opts {
   111  		opt(o)
   112  	}
   113  	return &LifeAdmin{opts: o}
   114  }