github.com/jtzjtz/kit@v1.0.2/conn/grpc_pool/grpc_pool.go (about) 1 package grpc_pool 2 3 import ( 4 "context" 5 "google.golang.org/grpc/connectivity" 6 "sync" 7 "time" 8 9 "google.golang.org/grpc" 10 ) 11 12 //GRPCPool conn info 13 type GRPCPool struct { 14 Mu sync.Mutex 15 IdleTimeout time.Duration 16 conns chan *grpcIdleConn 17 factory func() (*grpc.ClientConn, error) 18 close func(*grpc.ClientConn) error 19 maxConns int 20 minConns int 21 } 22 23 type grpcIdleConn struct { 24 conn *grpc.ClientConn 25 t time.Time 26 } 27 28 //Get get from conn 29 func (c *GRPCPool) Get() (*grpc.ClientConn, error) { 30 c.Mu.Lock() 31 conns := c.conns 32 c.Mu.Unlock() 33 34 if conns == nil { 35 return nil, errClosed 36 } 37 for { 38 select { 39 case wrapConn := <-conns: 40 if wrapConn == nil { 41 return nil, errClosed 42 } 43 //判断是否超时,超时则丢弃 44 if timeout := c.IdleTimeout; timeout > 0 { 45 if wrapConn.t.Add(timeout).Before(time.Now()) { 46 //丢弃并关闭该链接 47 c.close(wrapConn.conn) 48 continue 49 } 50 } 51 if wrapConn.conn.GetState() != connectivity.Ready { 52 c.close(wrapConn.conn) 53 continue 54 } 55 return wrapConn.conn, nil 56 default: 57 if c.IdleCount() >= c.maxConns { 58 return nil, errTooManyConns 59 } 60 conn, err := c.factory() 61 if err != nil { 62 return nil, err 63 } 64 return conn, nil 65 } 66 } 67 } 68 69 //Put put back to conn 70 func (c *GRPCPool) Put(conn *grpc.ClientConn) error { 71 if conn == nil { 72 return errRejected 73 } 74 75 c.Mu.Lock() 76 defer c.Mu.Unlock() 77 78 if c.conns == nil { 79 return c.close(conn) 80 } 81 82 select { 83 case c.conns <- &grpcIdleConn{conn: conn, t: time.Now()}: 84 return nil 85 default: 86 //连接池已满,直接关闭该链接 87 return c.close(conn) 88 } 89 } 90 91 //Close close conn 92 func (c *GRPCPool) Close() { 93 c.Mu.Lock() 94 conns := c.conns 95 c.conns = nil 96 c.factory = nil 97 closeFun := c.close 98 c.close = nil 99 c.Mu.Unlock() 100 101 if conns == nil { 102 return 103 } 104 105 close(conns) 106 for wrapConn := range conns { 107 closeFun(wrapConn.conn) 108 } 109 } 110 111 //IdleCount idle connection count 112 func (c *GRPCPool) IdleCount() int { 113 c.Mu.Lock() 114 conns := c.conns 115 c.Mu.Unlock() 116 return len(conns) 117 } 118 119 // 120 func (c *GRPCPool) CheckConn() { 121 for { 122 if len(c.conns) < c.minConns { 123 add := c.minConns - len(c.conns) 124 for i := 0; i < add; i++ { 125 conn, _ := c.factory() 126 c.Put(conn) 127 } 128 } 129 if len(c.conns) > c.minConns { 130 disc := len(c.conns) - c.minConns 131 c.Mu.Lock() 132 conns := c.conns 133 c.Mu.Unlock() 134 for i := 0; i < disc; i++ { 135 wrapConn := <-conns 136 c.close(wrapConn.conn) 137 } 138 } 139 time.Sleep(time.Second * 10) 140 } 141 } 142 143 //NewGRPCPool init grpc conn 144 func NewGRPCPool(o *Options, dialOptions ...grpc.DialOption) (*GRPCPool, error) { 145 if err := o.validate(); err != nil { 146 return nil, err 147 } 148 149 //init conn 150 pool := &GRPCPool{ 151 conns: make(chan *grpcIdleConn, o.MaxCap), 152 factory: func() (*grpc.ClientConn, error) { 153 target := o.nextTarget() 154 if target == "" { 155 return nil, errTargets 156 } 157 158 ctx, cancel := context.WithTimeout(context.Background(), o.DialTimeout) 159 defer cancel() 160 161 return grpc.DialContext(ctx, target, dialOptions...) 162 }, 163 close: func(v *grpc.ClientConn) error { return v.Close() }, 164 IdleTimeout: o.IdleTimeout, 165 maxConns: o.MaxCap, 166 minConns: o.InitCap, 167 } 168 169 //danamic update targets 170 o.update() 171 172 //init make conns 173 for i := 0; i < o.InitCap; i++ { 174 conn, err := pool.factory() 175 if err != nil { 176 pool.Close() 177 return nil, err 178 } 179 pool.conns <- &grpcIdleConn{conn: conn, t: time.Now()} 180 } 181 go pool.CheckConn() 182 return pool, nil 183 }