Redis: Support socket keepalive

redis-py supports socket keepalive feature. This updates the config
build process so that users can use this feature by the existing
socket keepalive options.

Change-Id: I396e7af9d1e1e04e56a11d26ffea506f2b675a18
This commit is contained in:
Takashi Kajinami 2024-02-18 03:14:03 +09:00
parent e8de6c9ea5
commit fd8d8889b8
3 changed files with 84 additions and 14 deletions

View File

@ -35,6 +35,7 @@ The library has special public value for nonexistent or expired keys called
NO_VALUE = core.NO_VALUE
"""
import re
import socket
import ssl
import urllib.parse
@ -311,21 +312,35 @@ def _build_cache_config(conf):
# and running or if it has broken.
# This could be used by users who want to handle fine grained failures.
if conf.cache.enable_socket_keepalive:
if conf.cache.backend != 'dogpile.cache.pymemcache':
msg = _(
"Socket keepalive is only supported by the "
"'dogpile.cache.pymemcache' backend."
if conf.cache.backend == 'dogpile.cache.pymemcache':
import pymemcache
socket_keepalive = pymemcache.KeepaliveOpts(
idle=conf.cache.socket_keepalive_idle,
intvl=conf.cache.socket_keepalive_interval,
cnt=conf.cache.socket_keepalive_count)
# As with the TLS context above, the config dict below will be
# consumed by dogpile.cache that will be used as a proxy between
# oslo.cache and pymemcache.
conf_dict['%s.arguments.socket_keepalive' % prefix] = \
socket_keepalive
elif conf.cache.backend in ('dogpile.cache.redis',
'dogpile.cache.redis_sentinel'):
socket_keepalive_options = {
socket.TCP_KEEPIDLE: conf.cache.socket_keepalive_idle,
socket.TCP_KEEPINTVL: conf.cache.socket_keepalive_interval,
socket.TCP_KEEPCNT: conf.cache.socket_keepalive_count
}
conf_dict.setdefault(
'%s.arguments.connection_kwargs' % prefix, {}
).update({
'socket_keepalive': True,
'socket_keepalive_options': socket_keepalive_options
})
else:
raise exception.ConfigurationError(
"Socket keepalive is not supported by the %s backend"
% conf.cache.backend
)
raise exception.ConfigurationError(msg)
import pymemcache
socket_keepalive = pymemcache.KeepaliveOpts(
idle=conf.cache.socket_keepalive_idle,
intvl=conf.cache.socket_keepalive_interval,
cnt=conf.cache.socket_keepalive_count)
# As with the TLS context above, the config dict below will be
# consumed by dogpile.cache that will be used as a proxy between
# oslo.cache and pymemcache.
conf_dict['%s.arguments.socket_keepalive' % prefix] = socket_keepalive
# NOTE(hberaud): The pymemcache library comes with retry mechanisms that
# can be used to wrap all kind of pymemcache clients. The retry wrapper

View File

@ -14,6 +14,7 @@
# under the License.
import copy
import socket
import ssl
import time
from unittest import mock
@ -769,6 +770,53 @@ class CacheRegionTest(test_cache.BaseTestCase):
self.assertEqual(
1.0, config_dict['test_prefix.arguments.socket_timeout'])
def test_cache_dictionary_config_builder_redis_with_keepalive(self):
"""Validate the backend is reset to default if caching is disabled."""
self.config_fixture.config(group='cache',
config_prefix='test_prefix',
backend='dogpile.cache.redis',
redis_server='[::1]:6379',
enable_socket_keepalive=True)
config_dict = cache._build_cache_config(self.config_fixture.conf)
self.assertEqual(
'redis://[::1]:6379',
config_dict['test_prefix.arguments.url'])
self.assertEqual(
1.0, config_dict['test_prefix.arguments.socket_timeout'])
self.assertEqual({
'socket_keepalive': True,
'socket_keepalive_options': {
socket.TCP_KEEPIDLE: 1,
socket.TCP_KEEPINTVL: 1,
socket.TCP_KEEPCNT: 1,
}}, config_dict['test_prefix.arguments.connection_kwargs'])
def test_cache_dictionary_config_builder_redis_with_keepalive_params(self):
"""Validate the backend is reset to default if caching is disabled."""
self.config_fixture.config(group='cache',
config_prefix='test_prefix',
backend='dogpile.cache.redis',
redis_server='[::1]:6379',
enable_socket_keepalive=True,
socket_keepalive_idle=2,
socket_keepalive_interval=3,
socket_keepalive_count=4)
config_dict = cache._build_cache_config(self.config_fixture.conf)
self.assertEqual(
'redis://[::1]:6379',
config_dict['test_prefix.arguments.url'])
self.assertEqual(
1.0, config_dict['test_prefix.arguments.socket_timeout'])
self.assertEqual({
'socket_keepalive': True,
'socket_keepalive_options': {
socket.TCP_KEEPIDLE: 2,
socket.TCP_KEEPINTVL: 3,
socket.TCP_KEEPCNT: 4,
}}, config_dict['test_prefix.arguments.connection_kwargs'])
def test_cache_dictionary_config_builder_redis_with_auth(self):
"""Validate the backend is reset to default if caching is disabled."""
self.config_fixture.config(group='cache',

View File

@ -0,0 +1,7 @@
---
features:
- |
The ``dogpile.cache.redis`` backend and ``dogpile.cache.redis_sentinel``
backend now supports enabling socket keepalive configurations by
setting the ``[cache] enable_socket_keepalive`` option to ``True``. Use
the ``socket_keepalive_*`` options to tune keepalive behavior.