11package pool
22
33import (
4+ "errors"
45 "sync"
56 "time"
67
@@ -12,37 +13,40 @@ import (
1213type pool struct {
1314 tr transport.Transport
1415
15- conns map [ string ][] * poolConn
16- size int
17- ttl time. Duration
18-
19- sync. Mutex
16+ closeTimeout time. Duration
17+ conns map [ string ][] * poolConn
18+ mu sync. Mutex
19+ size int
20+ ttl time. Duration
2021}
2122
2223type poolConn struct {
23- created time.Time
2424 transport.Client
25- id string
25+
26+ closeTimeout time.Duration
27+ created time.Time
28+ id string
2629}
2730
2831func newPool (options Options ) * pool {
2932 return & pool {
30- size : options .Size ,
31- tr : options .Transport ,
32- ttl : options .TTL ,
33- conns : make (map [string ][]* poolConn ),
33+ size : options .Size ,
34+ tr : options .Transport ,
35+ ttl : options .TTL ,
36+ closeTimeout : options .CloseTimeout ,
37+ conns : make (map [string ][]* poolConn ),
3438 }
3539}
3640
3741func (p * pool ) Close () error {
38- p .Lock ()
39- defer p .Unlock ()
42+ p .mu . Lock ()
43+ defer p .mu . Unlock ()
4044
4145 var err error
4246
4347 for k , c := range p .conns {
4448 for _ , conn := range c {
45- if nerr := conn .Client . Close (); nerr != nil {
49+ if nerr := conn .close (); nerr != nil {
4650 err = nerr
4751 }
4852 }
@@ -67,7 +71,7 @@ func (p *poolConn) Created() time.Time {
6771}
6872
6973func (p * pool ) Get (addr string , opts ... transport.DialOption ) (Conn , error ) {
70- p .Lock ()
74+ p .mu . Lock ()
7175 conns := p .conns [addr ]
7276
7377 // While we have conns check age and then return one
@@ -79,51 +83,77 @@ func (p *pool) Get(addr string, opts ...transport.DialOption) (Conn, error) {
7983
8084 // If conn is old kill it and move on
8185 if d := time .Since (conn .Created ()); d > p .ttl {
82- if err := conn .Client .Close (); err != nil {
83- p .Unlock ()
84- return nil , err
86+ if err := conn .close (); err != nil {
87+ p .mu .Unlock ()
88+ c , errConn := p .newConn (addr , opts )
89+ if errConn != nil {
90+ return nil , errConn
91+ }
92+ return c , err
8593 }
8694
8795 continue
8896 }
8997
9098 // We got a good conn, lets unlock and return it
91- p .Unlock ()
99+ p .mu . Unlock ()
92100
93101 return conn , nil
94102 }
95103
96- p .Unlock ()
104+ p .mu . Unlock ()
97105
106+ return p .newConn (addr , opts )
107+ }
108+
109+ func (p * pool ) newConn (addr string , opts []transport.DialOption ) (Conn , error ) {
98110 // create new conn
99111 c , err := p .tr .Dial (addr , opts ... )
100112 if err != nil {
101113 return nil , err
102114 }
103115
104116 return & poolConn {
105- Client : c ,
106- id : uuid .New ().String (),
107- created : time .Now (),
117+ Client : c ,
118+ id : uuid .New ().String (),
119+ closeTimeout : p .closeTimeout ,
120+ created : time .Now (),
108121 }, nil
109122}
110123
111124func (p * pool ) Release (conn Conn , err error ) error {
112125 // don't store the conn if it has errored
113126 if err != nil {
114- return conn .(* poolConn ).Client . Close ()
127+ return conn .(* poolConn ).close ()
115128 }
116129
117130 // otherwise put it back for reuse
118- p .Lock ()
119- defer p .Unlock ()
131+ p .mu . Lock ()
132+ defer p .mu . Unlock ()
120133
121134 conns := p .conns [conn .Remote ()]
122135 if len (conns ) >= p .size {
123- return conn .(* poolConn ).Client . Close ()
136+ return conn .(* poolConn ).close ()
124137 }
125138
126139 p .conns [conn .Remote ()] = append (conns , conn .(* poolConn ))
127140
128141 return nil
129142}
143+
144+ func (p * poolConn ) close () error {
145+ ch := make (chan error )
146+ go func () {
147+ defer close (ch )
148+ ch <- p .Client .Close ()
149+ }()
150+ t := time .NewTimer (p .closeTimeout )
151+ var err error
152+ select {
153+ case <- t .C :
154+ err = errors .New ("unable to close in time" )
155+ case err = <- ch :
156+ t .Stop ()
157+ }
158+ return err
159+ }
0 commit comments