Skip to content

Commit 783ca52

Browse files
committed
feat: Add PingingPool check on session age
1 parent d3fe937 commit 783ca52

File tree

2 files changed

+51
-1
lines changed

2 files changed

+51
-1
lines changed

google/cloud/spanner_v1/pool.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,8 @@ class PingingPool(AbstractSessionPool):
385385
:param database_role: (Optional) user-assigned database_role for the session.
386386
"""
387387

388+
SESSION_MAX_AGE = 28 * 24 * 60 * 60
389+
388390
def __init__(
389391
self,
390392
size=10,
@@ -448,8 +450,9 @@ def get(self, timeout=None):
448450
timeout = self.default_timeout
449451

450452
ping_after, session = self._sessions.get(block=True, timeout=timeout)
453+
session_age = (_NOW() - session._created_at).total_seconds()
451454

452-
if _NOW() > ping_after:
455+
if _NOW() > ping_after or session_age >= self.SESSION_MAX_AGE:
453456
# Using session.exists() guarantees the returned session exists.
454457
# session.ping() uses a cached result in the backend which could
455458
# result in a recently deleted session being returned.
@@ -481,6 +484,11 @@ def clear(self):
481484
else:
482485
session.delete()
483486

487+
def _new_session(self):
488+
session = super()._new_session()
489+
session._created_at = _NOW()
490+
return session
491+
484492
def ping(self):
485493
"""Refresh maybe-expired sessions in the pool.
486494

tests/unit/test_pool.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,48 @@ def test_get_hit_w_ping_expired(self):
531531
self.assertTrue(SESSIONS[0]._exists_checked)
532532
self.assertFalse(pool._sessions.full())
533533

534+
def test_get_hit_w_created(self):
535+
import datetime
536+
537+
pool = self._make_one(size=4)
538+
database = _Database("name")
539+
SESSIONS = [_Session(database)] * 4
540+
database._sessions.extend(SESSIONS)
541+
pool.bind(database)
542+
543+
session_max_age = 28 * 24 * 60 * 60
544+
SESSIONS[0]._created_at = datetime.datetime.utcnow() - datetime.timedelta(
545+
seconds=session_max_age + 10
546+
)
547+
548+
session = pool.get()
549+
550+
self.assertIs(session, SESSIONS[0])
551+
self.assertTrue(session._exists_checked)
552+
self.assertFalse(pool._sessions.full())
553+
554+
def test_get_hit_w_created_expired(self):
555+
import datetime
556+
557+
pool = self._make_one(size=4)
558+
database = _Database("name")
559+
SESSIONS = [_Session(database)] * 5
560+
database._sessions.extend(SESSIONS)
561+
pool.bind(database)
562+
563+
session_max_age = 28 * 24 * 60 * 60
564+
SESSIONS[0]._created_at = datetime.datetime.utcnow() - datetime.timedelta(
565+
seconds=session_max_age
566+
)
567+
SESSIONS[0]._exists = False
568+
569+
session = pool.get()
570+
571+
self.assertIs(session, SESSIONS[4])
572+
session.create.assert_called()
573+
self.assertTrue(SESSIONS[0]._exists_checked)
574+
self.assertFalse(pool._sessions.full())
575+
534576
def test_get_empty_default_timeout(self):
535577
import queue
536578

0 commit comments

Comments
 (0)