@@ -17,6 +17,7 @@ import (
17
17
18
18
var defaultMaxConns = int32 (4 )
19
19
var defaultMinConns = int32 (0 )
20
+ var defaultMinIdleConns = int32 (0 )
20
21
var defaultMaxConnLifetime = time .Hour
21
22
var defaultMaxConnIdleTime = time .Minute * 30
22
23
var defaultHealthCheckPeriod = time .Minute
@@ -87,6 +88,7 @@ type Pool struct {
87
88
afterRelease func (* pgx.Conn ) bool
88
89
beforeClose func (* pgx.Conn )
89
90
minConns int32
91
+ minIdleConns int32
90
92
maxConns int32
91
93
maxConnLifetime time.Duration
92
94
maxConnLifetimeJitter time.Duration
@@ -144,6 +146,13 @@ type Config struct {
144
146
// to create new connections.
145
147
MinConns int32
146
148
149
+ // MinIdleConns is the minimum number of idle connections in the pool. You can increase this to ensure that
150
+ // there are always idle connections available. This can help reduce tail latencies during request processing,
151
+ // as you can avoid the latency of establishing a new connection while handling requests. It is superior
152
+ // to MinConns for this purpose.
153
+ // Similar to MinConns, the pool might temporarily dip below MinIdleConns after connection closes.
154
+ MinIdleConns int32
155
+
147
156
// HealthCheckPeriod is the duration between checks of the health of idle connections.
148
157
HealthCheckPeriod time.Duration
149
158
@@ -189,6 +198,7 @@ func NewWithConfig(ctx context.Context, config *Config) (*Pool, error) {
189
198
afterRelease : config .AfterRelease ,
190
199
beforeClose : config .BeforeClose ,
191
200
minConns : config .MinConns ,
201
+ minIdleConns : config .MinIdleConns ,
192
202
maxConns : config .MaxConns ,
193
203
maxConnLifetime : config .MaxConnLifetime ,
194
204
maxConnLifetimeJitter : config .MaxConnLifetimeJitter ,
@@ -271,7 +281,8 @@ func NewWithConfig(ctx context.Context, config *Config) (*Pool, error) {
271
281
}
272
282
273
283
go func () {
274
- p .createIdleResources (ctx , int (p .minConns ))
284
+ targetIdleResources := max (int (p .minConns ), int (p .minIdleConns ))
285
+ p .createIdleResources (ctx , targetIdleResources )
275
286
p .backgroundHealthCheck ()
276
287
}()
277
288
@@ -334,6 +345,17 @@ func ParseConfig(connString string) (*Config, error) {
334
345
config .MinConns = defaultMinConns
335
346
}
336
347
348
+ if s , ok := config .ConnConfig .Config .RuntimeParams ["pool_min_idle_conns" ]; ok {
349
+ delete (connConfig .Config .RuntimeParams , "pool_min_idle_conns" )
350
+ n , err := strconv .ParseInt (s , 10 , 32 )
351
+ if err != nil {
352
+ return nil , fmt .Errorf ("cannot parse pool_min_idle_conns: %w" , err )
353
+ }
354
+ config .MinIdleConns = int32 (n )
355
+ } else {
356
+ config .MinIdleConns = defaultMinIdleConns
357
+ }
358
+
337
359
if s , ok := config .ConnConfig .Config .RuntimeParams ["pool_max_conn_lifetime" ]; ok {
338
360
delete (connConfig .Config .RuntimeParams , "pool_max_conn_lifetime" )
339
361
d , err := time .ParseDuration (s )
@@ -472,7 +494,9 @@ func (p *Pool) checkMinConns() error {
472
494
// TotalConns can include ones that are being destroyed but we should have
473
495
// sleep(500ms) around all of the destroys to help prevent that from throwing
474
496
// off this check
475
- toCreate := p .minConns - p .Stat ().TotalConns ()
497
+
498
+ // Create the number of connections needed to get to both minConns and minIdleConns
499
+ toCreate := max (p .minConns - p .Stat ().TotalConns (), p .minIdleConns - p .Stat ().IdleConns ())
476
500
if toCreate > 0 {
477
501
return p .createIdleResources (context .Background (), int (toCreate ))
478
502
}
0 commit comments