Skip to content

Commit 1142daf

Browse files
committed
dbapi: make global session pool and tie sessions to it
Apparently invoking spanner_v1.Database.session() by-passes using the provided session pool as advised at: googleapis/python-spanner#10 (comment) so this change using the logic that's provided with the context manager, but our use case to use Transactions with ORMs hadn't been thought of, so we have to use private methods and the methods used by spanner_v1.pool.SessionCheckout. Fixes #291
1 parent a038113 commit 1142daf

2 files changed

Lines changed: 29 additions & 8 deletions

File tree

packages/django-google-spanner/spanner/dbapi/__init__.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
# are working properly, we'll update the threadsafety level.
3131
threadsafety = 0
3232

33+
global_session_pool = spanner.pool.BurstyPool()
34+
3335

3436
def connect(project=None, instance=None, database=None, credentials_uri=None, user_agent=None):
3537
"""
@@ -68,11 +70,31 @@ def connect(project=None, instance=None, database=None, credentials_uri=None, us
6870
if not client_instance.exists():
6971
raise ProgrammingError("instance '%s' does not exist." % instance)
7072

71-
db = client_instance.database(database)
73+
db = client_instance.database(database, pool=global_session_pool)
7274
if not db.exists():
7375
raise ProgrammingError("database '%s' does not exist." % database)
7476

75-
return Connection(db)
77+
# Correctly retrieve a session from the global session pool.
78+
# See:
79+
# * https://github.com/orijtech/django-spanner/issues/291
80+
# * https://github.com/googleapis/python-spanner/issues/10#issuecomment-585056760
81+
#
82+
# Adapted from:
83+
# https://bit.ly/3c8MK6p: python-spanner, Git hash 997a03477b07ec39c7184
84+
# google/cloud/spanner_v1/pool.py#L514-L535
85+
# TODO: File a bug to googleapis/python-spanner asking for a convenience
86+
# method since invoke database.session() gives the wrong result
87+
# yet requires a context manager wrapped with SessionCheckout
88+
# and needs accessing private methods, which leaks the details of the
89+
# implementation in order to try to use it correctly.
90+
pool = db._pool
91+
session_checkout = spanner.pool.SessionCheckout(pool)
92+
session = session_checkout.__enter__()
93+
if not session.exists():
94+
session.create()
95+
return_session = lambda: session_checkout.__exit__() # noqa
96+
97+
return Connection(db, session, return_session)
7698

7799

78100
__all__ = [

packages/django-google-spanner/spanner/dbapi/connection.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,9 @@
1010

1111

1212
class Connection(object):
13-
def __init__(self, db_handle):
14-
sess = db_handle.session()
15-
if not sess.exists():
16-
sess.create()
17-
self.__sess = sess
13+
def __init__(self, db_handle, session, discard_session):
14+
self.__sess = session
15+
self.__discard_session = discard_session
1816
self.__txn = None
1917
self.__dbhandle = db_handle
2018
self.__closed = False
@@ -37,7 +35,8 @@ def __enter__(self):
3735

3836
def __clear(self):
3937
self.__dbhandle = None
40-
self.__sess.delete()
38+
self.__discard_session()
39+
self.__sess = None
4140

4241
def __exit__(self, etype, value, traceback):
4342
self.__raise_if_already_closed()

0 commit comments

Comments
 (0)