Skip to content

Commit 46b0828

Browse files
smartconnpool: fix MaxLifetime jitter (#20118)
Signed-off-by: Arthur Schreiber <arthur@planetscale.com>
1 parent 65c9959 commit 46b0828

2 files changed

Lines changed: 42 additions & 2 deletions

File tree

go/pools/smartconnpool/pool.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -526,10 +526,10 @@ func (pool *ConnPool[C]) closeOnIdleLimitReached(conn *Pooled[C]) bool {
526526

527527
func (pool *ConnPool[D]) extendedMaxLifetime() time.Duration {
528528
maxLifetime := pool.config.maxLifetime.Load()
529-
if maxLifetime == 0 {
529+
if maxLifetime <= 0 {
530530
return 0
531531
}
532-
return time.Duration(maxLifetime) + time.Duration(rand.Uint32N(uint32(maxLifetime)))
532+
return time.Duration(maxLifetime) + time.Duration(rand.Int64N(maxLifetime))
533533
}
534534

535535
func (pool *ConnPool[C]) connReopen(ctx context.Context, dbconn *Pooled[C], now time.Duration) (err error) {

go/pools/smartconnpool/pool_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,46 @@ func TestExtendedLifetimeTimeout(t *testing.T) {
812812
}
813813
}
814814

815+
func TestExtendedMaxLifetimeJitter(t *testing.T) {
816+
var state TestState
817+
config := &Config[*TestConn]{
818+
Capacity: 1,
819+
MaxLifetime: 30 * time.Minute,
820+
LogWait: state.LogWait,
821+
}
822+
823+
p := NewPool(config).Open(newConnector(&state), nil)
824+
t.Cleanup(p.Close)
825+
826+
threshold := config.MaxLifetime + config.MaxLifetime/2
827+
const maxAttempts = 64
828+
829+
for range maxAttempts {
830+
extended := p.extendedMaxLifetime()
831+
require.LessOrEqual(t, config.MaxLifetime, extended)
832+
require.Greater(t, 2*config.MaxLifetime, extended)
833+
834+
if extended > threshold {
835+
return
836+
}
837+
}
838+
839+
require.Failf(t, "jitter never reached upper half of range",
840+
"no sample in %d tries exceeded %s", maxAttempts, threshold)
841+
}
842+
843+
func TestExtendedMaxLifetimeNegativeDisables(t *testing.T) {
844+
var state TestState
845+
p := NewPool(&Config[*TestConn]{
846+
Capacity: 1,
847+
MaxLifetime: -1 * time.Second,
848+
LogWait: state.LogWait,
849+
}).Open(newConnector(&state), nil)
850+
t.Cleanup(p.Close)
851+
852+
require.EqualValues(t, 0, p.extendedMaxLifetime())
853+
}
854+
815855
// TestMaxIdleCount tests the MaxIdleCount setting, to check if the pool closes
816856
// the idle connections when the number of idle connections exceeds the limit.
817857
func TestMaxIdleCount(t *testing.T) {

0 commit comments

Comments
 (0)