@@ -36,6 +36,8 @@ class which can be used to obtain `Driver` instances that are used for
36
36
from .typesystem import hydrated
37
37
38
38
39
+ DEFAULT_MAX_POOL_SIZE = 50
40
+
39
41
STATEMENT_TYPE_READ_ONLY = "r"
40
42
STATEMENT_TYPE_READ_WRITE = "rw"
41
43
STATEMENT_TYPE_WRITE_ONLY = "w"
@@ -91,7 +93,8 @@ def __init__(self, url, **config):
91
93
else :
92
94
raise ValueError ("Unsupported URL scheme: %s" % parsed .scheme )
93
95
self .config = config
94
- self .sessions = deque ()
96
+ self .max_pool_size = config .get ("max_pool_size" , DEFAULT_MAX_POOL_SIZE )
97
+ self .session_pool = deque ()
95
98
96
99
def session (self ):
97
100
""" Create a new session based on the graph database details
@@ -102,14 +105,33 @@ def session(self):
102
105
>>> session = driver.session()
103
106
104
107
"""
105
- try :
106
- session = self .sessions .pop ()
107
- except IndexError :
108
- session = Session (self )
109
- else :
110
- session .connection .reset ()
108
+ session = None
109
+ done = False
110
+ while not done :
111
+ try :
112
+ session = self .session_pool .pop ()
113
+ except IndexError :
114
+ session = Session (self )
115
+ done = True
116
+ else :
117
+ if session .healthy :
118
+ session .connection .reset ()
119
+ done = session .healthy
111
120
return session
112
121
122
+ def recycle (self , session ):
123
+ """ Pass a session back to the driver for recycling, if healthy.
124
+
125
+ :param session:
126
+ :return:
127
+ """
128
+ pool = self .session_pool
129
+ for s in pool :
130
+ if not s .healthy :
131
+ pool .remove (s )
132
+ if session .healthy and len (pool ) < self .max_pool_size and session not in pool :
133
+ pool .appendleft (session )
134
+
113
135
114
136
class Result (list ):
115
137
""" A handler for the result of Cypher statement execution.
@@ -344,19 +366,25 @@ def __init__(self, driver):
344
366
self .connection = connect (driver .host , driver .port , ** driver .config )
345
367
self .transaction = None
346
368
self .bench_tests = []
347
- self .closed = False
348
369
349
370
def __del__ (self ):
350
- if not self .closed :
371
+ if not self .connection . closed :
351
372
self .connection .close ()
352
- self .closed = True
353
373
354
374
def __enter__ (self ):
355
375
return self
356
376
357
377
def __exit__ (self , exc_type , exc_value , traceback ):
358
378
self .close ()
359
379
380
+ @property
381
+ def healthy (self ):
382
+ """ Return ``True`` if this session is healthy, ``False`` if
383
+ unhealthy and ``None`` if closed.
384
+ """
385
+ connection = self .connection
386
+ return None if connection .closed else not connection .defunct
387
+
360
388
def run (self , statement , parameters = None ):
361
389
""" Run a parameterised Cypher statement.
362
390
@@ -411,9 +439,7 @@ def run(self, statement, parameters=None):
411
439
def close (self ):
412
440
""" If still usable, return this session to the driver pool it came from.
413
441
"""
414
- if not self .connection .defunct :
415
- self .driver .sessions .appendleft (self )
416
- self .closed = True
442
+ self .driver .recycle (self )
417
443
418
444
def begin_transaction (self ):
419
445
""" Create a new :class:`.Transaction` within this session.
0 commit comments