Added PoolingConnection for non thread-safe connection classes
This commit is contained in:
@@ -6,9 +6,9 @@ except ImportError:
|
|||||||
from urllib.parse import urlencode
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
from ..exceptions import TransportError, ConnectionError
|
from ..exceptions import TransportError, ConnectionError
|
||||||
from .base import Connection
|
from .pooling import PoolingConnection
|
||||||
|
|
||||||
class MemcachedConnection(Connection):
|
class MemcachedConnection(PoolingConnection):
|
||||||
transport_schema = 'memcached'
|
transport_schema = 'memcached'
|
||||||
|
|
||||||
method_map = {
|
method_map = {
|
||||||
@@ -25,9 +25,10 @@ class MemcachedConnection(Connection):
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
raise ImproperlyConfigured("You need to install pylibmc to use the MemcachedConnection class.")
|
raise ImproperlyConfigured("You need to install pylibmc to use the MemcachedConnection class.")
|
||||||
super(MemcachedConnection, self).__init__(host=host, port=port, **kwargs)
|
super(MemcachedConnection, self).__init__(host=host, port=port, **kwargs)
|
||||||
self.mc = pylibmc.Client(['%s:%s' % (host, port)],behaviors={"tcp_nodelay": True})
|
self._make_connection = lambda: pylibmc.Client(['%s:%s' % (host, port)], behaviors={"tcp_nodelay": True})
|
||||||
|
|
||||||
def perform_request(self, method, url, params=None, body=None, timeout=None):
|
def perform_request(self, method, url, params=None, body=None, timeout=None):
|
||||||
|
mc = self._get_connection()
|
||||||
url = self.url_prefix + url
|
url = self.url_prefix + url
|
||||||
if params:
|
if params:
|
||||||
url = '%s?%s' % (url, urlencode(params or {}))
|
url = '%s?%s' % (url, urlencode(params or {}))
|
||||||
@@ -41,10 +42,10 @@ class MemcachedConnection(Connection):
|
|||||||
if mc_method == 'set':
|
if mc_method == 'set':
|
||||||
# no response from set commands
|
# no response from set commands
|
||||||
response = ''
|
response = ''
|
||||||
if not json.dumps(self.mc.set(url, body)):
|
if not json.dumps(mc.set(url, body)):
|
||||||
status = 500
|
status = 500
|
||||||
else:
|
else:
|
||||||
response = self.mc.get(url)
|
response = mc.get(url)
|
||||||
|
|
||||||
duration = time.time() - start
|
duration = time.time() - start
|
||||||
if response:
|
if response:
|
||||||
@@ -52,6 +53,8 @@ class MemcachedConnection(Connection):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log_request_fail(method, full_url, time.time() - start, exception=e)
|
self.log_request_fail(method, full_url, time.time() - start, exception=e)
|
||||||
raise ConnectionError('N/A', str(e), e)
|
raise ConnectionError('N/A', str(e), e)
|
||||||
|
finally:
|
||||||
|
self._release_connection(mc)
|
||||||
|
|
||||||
# try not to load the json every time
|
# try not to load the json every time
|
||||||
if response and response[0] == '{' and ('"status"' in response or '"error"' in response):
|
if response and response[0] == '{' and ('"status"' in response or '"error"' in response):
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
from .base import Connection
|
||||||
|
|
||||||
|
class PoolingConnection(Connection):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
self._max_pool_size = kwargs.pop('max_connection_pool_size', 50)
|
||||||
|
self._free_connections = []
|
||||||
|
self._in_use_connections = set()
|
||||||
|
super(PoolingConnection, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def _get_connection(self):
|
||||||
|
try:
|
||||||
|
con = self._free_connections.pop()
|
||||||
|
except IndexError:
|
||||||
|
con = self._make_connection()
|
||||||
|
|
||||||
|
self._in_use_connections.add(con)
|
||||||
|
return con
|
||||||
|
|
||||||
|
def _release_connection(self, con):
|
||||||
|
self._in_use_connections.remove(con)
|
||||||
|
self._free_connections.append(con)
|
||||||
|
|
||||||
@@ -12,9 +12,9 @@ except ImportError:
|
|||||||
THRIFT_AVAILABLE = False
|
THRIFT_AVAILABLE = False
|
||||||
|
|
||||||
from ..exceptions import ConnectionError
|
from ..exceptions import ConnectionError
|
||||||
from .base import Connection
|
from .pooling import PoolingConnection
|
||||||
|
|
||||||
class ThriftConnection(Connection):
|
class ThriftConnection(PoolingConnection):
|
||||||
transport_schema = 'thrift'
|
transport_schema = 'thrift'
|
||||||
|
|
||||||
def __init__(self, host='localhost', port=9500, framed_transport=False, **kwargs):
|
def __init__(self, host='localhost', port=9500, framed_transport=False, **kwargs):
|
||||||
@@ -22,9 +22,13 @@ class ThriftConnection(Connection):
|
|||||||
raise ImproperlyConfigured("Thrift is not available.")
|
raise ImproperlyConfigured("Thrift is not available.")
|
||||||
|
|
||||||
super(ThriftConnection, self).__init__(host=host, port=port, **kwargs)
|
super(ThriftConnection, self).__init__(host=host, port=port, **kwargs)
|
||||||
socket = TSocket.TSocket(host, port)
|
self._framed_transport = framed_transport
|
||||||
|
self._tsocket_args = (host, port)
|
||||||
|
|
||||||
|
def _make_connection(self):
|
||||||
|
socket = TSocket.TSocket(*self._tsocket_args)
|
||||||
socket.setTimeout(self.timeout * 1000.0)
|
socket.setTimeout(self.timeout * 1000.0)
|
||||||
if framed_transport:
|
if self._framed_transport:
|
||||||
transport = TTransport.TFramedTransport(socket)
|
transport = TTransport.TFramedTransport(socket)
|
||||||
else:
|
else:
|
||||||
transport = TTransport.TBufferedTransport(socket)
|
transport = TTransport.TBufferedTransport(socket)
|
||||||
@@ -32,20 +36,22 @@ class ThriftConnection(Connection):
|
|||||||
protocol = TBinaryProtocol.TBinaryProtocolAccelerated(transport)
|
protocol = TBinaryProtocol.TBinaryProtocolAccelerated(transport)
|
||||||
client = Rest.Client(protocol)
|
client = Rest.Client(protocol)
|
||||||
transport.open()
|
transport.open()
|
||||||
self.tclient = client
|
return client
|
||||||
self.ttransport = transport
|
|
||||||
|
|
||||||
def perform_request(self, method, url, params=None, body=None, timeout=None):
|
def perform_request(self, method, url, params=None, body=None, timeout=None):
|
||||||
request = RestRequest(method=Method._NAMES_TO_VALUES[method.upper()], uri=url,
|
request = RestRequest(method=Method._NAMES_TO_VALUES[method.upper()], uri=url,
|
||||||
parameters=params, body=body)
|
parameters=params, body=body)
|
||||||
|
|
||||||
start = time.time()
|
start = time.time()
|
||||||
|
tclient = self._get_connection()
|
||||||
try:
|
try:
|
||||||
response = self.tclient.execute(request)
|
response = tclient.execute(request)
|
||||||
duration = time.time() - start
|
duration = time.time() - start
|
||||||
except TException as e:
|
except TException as e:
|
||||||
self.log_request_fail(method, url, time.time() - start, exception=e)
|
self.log_request_fail(method, url, time.time() - start, exception=e)
|
||||||
raise ConnectionError('N/A', str(e), e)
|
raise ConnectionError('N/A', str(e), e)
|
||||||
|
finally:
|
||||||
|
self._release_connection(tclient)
|
||||||
|
|
||||||
if not (200 <= response.status < 300):
|
if not (200 <= response.status < 300):
|
||||||
self.log_request_fail(method, url, duration, response.status)
|
self.log_request_fail(method, url, duration, response.status)
|
||||||
|
|||||||
Reference in New Issue
Block a user