github.com/zly-app/zapp@v1.3.3/component/conn/conn.go (about)

     1  /*
     2  -------------------------------------------------
     3     Author :       zlyuancn
     4     date:         2021/1/1
     5     Description :
     6  -------------------------------------------------
     7  */
     8  
     9  package conn
    10  
    11  import (
    12  	"sync"
    13  
    14  	"go.uber.org/zap"
    15  
    16  	"github.com/zly-app/zapp/consts"
    17  	"github.com/zly-app/zapp/logger"
    18  	"github.com/zly-app/zapp/pkg/utils"
    19  )
    20  
    21  type CreatorFunc = func(name string) (IInstance, error)
    22  
    23  type IInstance interface {
    24  	Close()
    25  }
    26  
    27  // 连接器
    28  type Conn struct {
    29  	wgs map[string]*connWaitGroup
    30  	mx  sync.RWMutex
    31  }
    32  
    33  type connWaitGroup struct {
    34  	instance IInstance
    35  	e        error
    36  	wg       sync.WaitGroup
    37  }
    38  
    39  func NewConn() *Conn {
    40  	return &Conn{
    41  		wgs: make(map[string]*connWaitGroup),
    42  	}
    43  }
    44  
    45  // 获取实例
    46  func (c *Conn) GetInstance(creator CreatorFunc, name ...string) IInstance {
    47  	if len(name) == 0 {
    48  		return c.getInstance(creator, consts.DefaultComponentName)
    49  	}
    50  	return c.getInstance(creator, name[0])
    51  }
    52  
    53  func (c *Conn) getInstance(creator CreatorFunc, name string) IInstance {
    54  	c.mx.RLock()
    55  	wg, ok := c.wgs[name]
    56  	c.mx.RUnlock()
    57  
    58  	if ok {
    59  		wg.wg.Wait()
    60  		if wg.e != nil {
    61  			logger.Log.Panic(wg.e.Error(), zap.String("name", name))
    62  		}
    63  		return wg.instance
    64  	}
    65  
    66  	c.mx.Lock()
    67  
    68  	// 再获取一次, 它可能在获取锁的过程中完成了
    69  	if wg, ok = c.wgs[name]; ok {
    70  		c.mx.Unlock()
    71  		wg.wg.Wait()
    72  		if wg.e != nil {
    73  			logger.Log.Panic(wg.e.Error(), zap.String("name", name))
    74  		}
    75  		return wg.instance
    76  	}
    77  
    78  	// 占位置
    79  	wg = new(connWaitGroup)
    80  	wg.wg.Add(1)
    81  	c.wgs[name] = wg
    82  	c.mx.Unlock()
    83  
    84  	var err error
    85  	err = utils.Recover.WrapCall(func() error {
    86  		wg.instance, err = creator(name)
    87  		return err
    88  	})
    89  
    90  	// 如果出现错误, 删除占位
    91  	if err != nil {
    92  		wg.e = err
    93  		wg.wg.Done()
    94  		c.mx.Lock()
    95  		delete(c.wgs, name)
    96  		c.mx.Unlock()
    97  		logger.Log.Panic(utils.Recover.GetRecoverErrorDetail(wg.e), zap.String("name", name))
    98  	}
    99  
   100  	wg.wg.Done()
   101  	return wg.instance
   102  }
   103  
   104  // 移除实例, 移除时会关闭示例
   105  func (c *Conn) Remove(name string) {
   106  	c.mx.Lock()
   107  	defer c.mx.Unlock()
   108  	wg, ok := c.wgs[name]
   109  	if ok {
   110  		wg.instance.Close()
   111  		delete(c.wgs, name)
   112  	}
   113  }
   114  
   115  // 关闭所有实例的链接
   116  func (c *Conn) CloseAll() {
   117  	c.mx.Lock()
   118  	defer c.mx.Unlock()
   119  
   120  	for _, wg := range c.wgs {
   121  		if wg.instance != nil {
   122  			wg.instance.Close()
   123  		}
   124  	}
   125  	c.wgs = make(map[string]*connWaitGroup)
   126  }