[PATCH 6 of 9 cubicweb] [server] dynamically close idle database connections
Philippe Pepiot
ph at itsalwaysdns.eu
Tue Mar 31 18:29:01 CEST 2020
# HG changeset patch
# User Philippe Pepiot <ph at itsalwaysdns.eu>
# Date 1585575972 -7200
# Mon Mar 30 15:46:12 2020 +0200
# Node ID e49e03b590e087b88d1d79f0472ccf5eac62c0e2
# Parent 85ae938eed132372bc3726da59b01d8c5b9da5ab
# Available At https://philpep.org/pub/hg/cubicweb
# hg pull https://philpep.org/pub/hg/cubicweb -r e49e03b590e0
[server] dynamically close idle database connections
When pool hasn't been empty for `idle_timeout` time, start closing connections.
diff --git a/cubicweb/server/repository.py b/cubicweb/server/repository.py
--- a/cubicweb/server/repository.py
+++ b/cubicweb/server/repository.py
@@ -31,6 +31,7 @@ from contextlib import contextmanager
from logging import getLogger
import queue
import threading
+import time
from logilab.common.decorators import cached, clear_cache
@@ -171,13 +172,15 @@ class _BaseCnxSet:
class _CnxSetPool(_BaseCnxSet):
- def __init__(self, source, min_size=1, max_size=4):
+ def __init__(self, source, min_size=1, max_size=4, idle_timeout=300):
super().__init__(source)
self._cnxsets = []
self._queue = queue.LifoQueue()
self.lock = threading.Lock()
self.min_size = min_size
self.max_size = max_size
+ self.idle = time.time()
+ self.idle_timeout = idle_timeout
for i in range(min_size):
self._queue.put_nowait(self._new_cnxset())
@@ -188,6 +191,19 @@ class _CnxSetPool(_BaseCnxSet):
self._cnxsets.append(cnxset)
return cnxset
+ def _close_idle_cnxset(self):
+ # close connections not being used since idle_timeout
+ if abs(time.time() - self.idle) > self.idle_timeout and self.size() > self.min_size:
+ try:
+ cnxset = self._queue.get_nowait()
+ except queue.Empty:
+ # the queue has been used since we checked it size
+ pass
+ else:
+ cnxset.close(True)
+ with self.lock:
+ self._cnxsets.remove(cnxset)
+
def size(self):
with self.lock:
return len(self._cnxsets)
@@ -198,8 +214,11 @@ class _CnxSetPool(_BaseCnxSet):
def get(self):
try:
cnxset = self._queue.get_nowait()
+ self._close_idle_cnxset()
return cnxset
except queue.Empty:
+ # reset idle time
+ self.idle = time.time()
if self.max_size and self.size() >= self.max_size:
try:
return self._queue.get(True, timeout=5)
@@ -213,6 +232,7 @@ class _CnxSetPool(_BaseCnxSet):
def release(self, cnxset):
self._queue.put_nowait(cnxset)
+ self._close_idle_cnxset()
def __iter__(self):
with self.lock:
More information about the cubicweb-devel
mailing list