Skip to content

Commit 0ffc298

Browse files
committed
Removed use_cache, make health_check configurable, removed retry logic around can_read()
1 parent fa1a431 commit 0ffc298

File tree

8 files changed

+215
-190
lines changed

8 files changed

+215
-190
lines changed

redis/cache.py

Lines changed: 43 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ def __init__(
3939
self.cache_value = cache_value
4040
self.status = status
4141

42+
def __hash__(self):
43+
return hash((self.cache_key, self.cache_value, self.status))
44+
45+
def __eq__(self, other):
46+
return hash(self) == hash(other)
47+
4248

4349
class EvictionPolicyInterface(ABC):
4450
@property
@@ -68,63 +74,71 @@ def touch(self, cache_key: CacheKey) -> None:
6874
pass
6975

7076

71-
class CacheInterface(ABC):
77+
class CacheConfigurationInterface(ABC):
7278
@abstractmethod
73-
def get_collection(self) -> OrderedDict:
79+
def get_cache_class(self):
7480
pass
7581

7682
@abstractmethod
77-
def get_eviction_policy(self) -> EvictionPolicyInterface:
83+
def get_max_size(self) -> int:
7884
pass
7985

8086
@abstractmethod
81-
def get_max_size(self) -> int:
87+
def get_eviction_policy(self):
8288
pass
8389

8490
@abstractmethod
85-
def get(self, key: CacheKey) -> Union[CacheEntry, None]:
91+
def get_health_check_interval(self) -> float:
8692
pass
8793

8894
@abstractmethod
89-
def set(self, entry: CacheEntry) -> bool:
95+
def is_exceeds_max_size(self, count: int) -> bool:
9096
pass
9197

9298
@abstractmethod
93-
def delete_by_cache_keys(self, cache_keys: List[CacheKey]) -> List[bool]:
99+
def is_allowed_to_cache(self, command: str) -> bool:
94100
pass
95101

102+
103+
class CacheInterface(ABC):
96104
@abstractmethod
97-
def delete_by_redis_keys(self, redis_keys: List[bytes]) -> List[bool]:
105+
def get_collection(self) -> OrderedDict:
98106
pass
99107

100108
@abstractmethod
101-
def flush(self) -> int:
109+
def get_config(self) -> CacheConfigurationInterface:
102110
pass
103111

104112
@abstractmethod
105-
def is_cachable(self, key: CacheKey) -> bool:
113+
def get_eviction_policy(self) -> EvictionPolicyInterface:
106114
pass
107115

116+
@abstractmethod
117+
def get_size(self) -> int:
118+
pass
108119

109-
class CacheConfigurationInterface(ABC):
110120
@abstractmethod
111-
def get_cache_class(self):
121+
def get(self, key: CacheKey) -> Union[CacheEntry, None]:
112122
pass
113123

114124
@abstractmethod
115-
def get_max_size(self) -> int:
125+
def set(self, entry: CacheEntry) -> bool:
116126
pass
117127

118128
@abstractmethod
119-
def get_eviction_policy(self):
129+
def delete_by_cache_keys(self, cache_keys: List[CacheKey]) -> List[bool]:
120130
pass
121131

122132
@abstractmethod
123-
def is_exceeds_max_size(self, count: int) -> bool:
133+
def delete_by_redis_keys(self, redis_keys: List[bytes]) -> List[bool]:
124134
pass
125135

126136
@abstractmethod
127-
def is_allowed_to_cache(self, command: str) -> bool:
137+
def flush(self) -> int:
138+
pass
139+
140+
@abstractmethod
141+
def is_cachable(self, key: CacheKey) -> bool:
128142
pass
129143

130144

@@ -141,11 +155,14 @@ def __init__(
141155
def get_collection(self) -> OrderedDict:
142156
return self._cache
143157

158+
def get_config(self) -> CacheConfigurationInterface:
159+
return self._cache_config
160+
144161
def get_eviction_policy(self) -> EvictionPolicyInterface:
145162
return self._eviction_policy
146163

147-
def get_max_size(self) -> int:
148-
return self._cache_config.get_max_size()
164+
def get_size(self) -> int:
165+
return len(self._cache)
149166

150167
def set(self, entry: CacheEntry) -> bool:
151168
if not self.is_cachable(entry.cache_key):
@@ -256,7 +273,7 @@ class EvictionPolicy(Enum):
256273
LRU = LRUPolicy
257274

258275

259-
class CacheConfiguration(CacheConfigurationInterface):
276+
class CacheConfig(CacheConfigurationInterface):
260277
DEFAULT_CACHE_CLASS = DefaultCache
261278
DEFAULT_EVICTION_POLICY = EvictionPolicy.LRU
262279
DEFAULT_MAX_SIZE = 10000
@@ -343,10 +360,12 @@ def __init__(
343360
max_size: int = DEFAULT_MAX_SIZE,
344361
cache_class: Any = DEFAULT_CACHE_CLASS,
345362
eviction_policy: EvictionPolicy = DEFAULT_EVICTION_POLICY,
363+
health_check_interval: float = 2.0,
346364
):
347365
self._cache_class = cache_class
348366
self._max_size = max_size
349367
self._eviction_policy = eviction_policy
368+
self._health_check_interval = health_check_interval
350369

351370
def get_cache_class(self):
352371
return self._cache_class
@@ -357,6 +376,9 @@ def get_max_size(self) -> int:
357376
def get_eviction_policy(self) -> EvictionPolicy:
358377
return self._eviction_policy
359378

379+
def get_health_check_interval(self) -> float:
380+
return self._health_check_interval
381+
360382
def is_exceeds_max_size(self, count: int) -> bool:
361383
return count > self._max_size
362384

@@ -371,11 +393,11 @@ def get_cache(self) -> CacheInterface:
371393

372394

373395
class CacheFactory(CacheFactoryInterface):
374-
def __init__(self, cache_config: Optional[CacheConfiguration] = None):
396+
def __init__(self, cache_config: Optional[CacheConfig] = None):
375397
self._config = cache_config
376398

377399
if self._config is None:
378-
self._config = CacheConfiguration()
400+
self._config = CacheConfig()
379401

380402
def get_cache(self) -> CacheInterface:
381403
cache_class = self._config.get_cache_class()

redis/client.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
_RedisCallbacksRESP3,
1414
bool_ok,
1515
)
16-
from redis.cache import CacheConfiguration, CacheInterface
16+
from redis.cache import CacheConfig, CacheInterface
1717
from redis.commands import (
1818
CoreCommands,
1919
RedisModuleCommands,
@@ -142,12 +142,10 @@ class initializer. In the case of conflicting arguments, querystring
142142
143143
"""
144144
single_connection_client = kwargs.pop("single_connection_client", False)
145-
use_cache = kwargs.pop("use_cache", False)
146145
connection_pool = ConnectionPool.from_url(url, **kwargs)
147146
client = cls(
148147
connection_pool=connection_pool,
149148
single_connection_client=single_connection_client,
150-
use_cache=use_cache,
151149
)
152150
client.auto_close_connection_pool = True
153151
return client
@@ -213,9 +211,8 @@ def __init__(
213211
redis_connect_func=None,
214212
credential_provider: Optional[CredentialProvider] = None,
215213
protocol: Optional[int] = 2,
216-
use_cache: bool = False,
217214
cache: Optional[CacheInterface] = None,
218-
cache_config: Optional[CacheConfiguration] = None,
215+
cache_config: Optional[CacheConfig] = None,
219216
) -> None:
220217
"""
221218
Initialize a new Redis client.
@@ -308,10 +305,9 @@ def __init__(
308305
"ssl_ciphers": ssl_ciphers,
309306
}
310307
)
311-
if use_cache and protocol in [3, "3"]:
308+
if (cache_config or cache) and protocol in [3, "3"]:
312309
kwargs.update(
313310
{
314-
"use_cache": use_cache,
315311
"cache": cache,
316312
"cache_config": cache_config,
317313
}
@@ -323,7 +319,7 @@ def __init__(
323319

324320
self.connection_pool = connection_pool
325321

326-
if use_cache and self.connection_pool.get_protocol() not in [3, "3"]:
322+
if (cache_config or cache) and self.connection_pool.get_protocol() not in [3, "3"]:
327323
raise RedisError("Client caching is only supported with RESP version 3")
328324

329325
self.connection = None

redis/cluster.py

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from redis._parsers import CommandsParser, Encoder
1010
from redis._parsers.helpers import parse_scan
1111
from redis.backoff import default_backoff
12-
from redis.cache import CacheConfiguration, CacheInterface
12+
from redis.cache import CacheConfig, CacheInterface
1313
from redis.client import CaseInsensitiveDict, PubSub, Redis
1414
from redis.commands import READ_COMMANDS, RedisClusterCommands
1515
from redis.commands.helpers import list_or_args
@@ -168,7 +168,6 @@ def parse_cluster_myshardid(resp, **options):
168168
"ssl_password",
169169
"unix_socket_path",
170170
"username",
171-
"use_cache",
172171
"cache",
173172
"cache_config",
174173
)
@@ -504,9 +503,8 @@ def __init__(
504503
dynamic_startup_nodes: bool = True,
505504
url: Optional[str] = None,
506505
address_remap: Optional[Callable[[Tuple[str, int]], Tuple[str, int]]] = None,
507-
use_cache: bool = False,
508506
cache: Optional[CacheInterface] = None,
509-
cache_config: Optional[CacheConfiguration] = None,
507+
cache_config: Optional[CacheConfig] = None,
510508
**kwargs,
511509
):
512510
"""
@@ -631,7 +629,7 @@ def __init__(
631629
kwargs.get("decode_responses", False),
632630
)
633631
protocol = kwargs.get("protocol", None)
634-
if use_cache and protocol not in [3, "3"]:
632+
if (cache_config or cache) and protocol not in [3, "3"]:
635633
raise RedisError("Client caching is only supported with RESP version 3")
636634

637635
self.cluster_error_retry_attempts = cluster_error_retry_attempts
@@ -646,7 +644,6 @@ def __init__(
646644
require_full_coverage=require_full_coverage,
647645
dynamic_startup_nodes=dynamic_startup_nodes,
648646
address_remap=address_remap,
649-
use_cache=use_cache,
650647
cache=cache,
651648
cache_config=cache_config,
652649
**kwargs,
@@ -1328,9 +1325,8 @@ def __init__(
13281325
dynamic_startup_nodes=True,
13291326
connection_pool_class=ConnectionPool,
13301327
address_remap: Optional[Callable[[Tuple[str, int]], Tuple[str, int]]] = None,
1331-
use_cache: bool = False,
13321328
cache: Optional[CacheInterface] = None,
1333-
cache_config: Optional[CacheConfiguration] = None,
1329+
cache_config: Optional[CacheConfig] = None,
13341330
**kwargs,
13351331
):
13361332
self.nodes_cache = {}
@@ -1343,7 +1339,6 @@ def __init__(
13431339
self._dynamic_startup_nodes = dynamic_startup_nodes
13441340
self.connection_pool_class = connection_pool_class
13451341
self.address_remap = address_remap
1346-
self.use_cache = use_cache
13471342
self.cache = cache
13481343
self.cache_config = cache_config
13491344
self._moved_exception = None
@@ -1489,15 +1484,13 @@ def create_redis_node(self, host, port, **kwargs):
14891484
# Create a redis node with a costumed connection pool
14901485
kwargs.update({"host": host})
14911486
kwargs.update({"port": port})
1492-
kwargs.update({"use_cache": self.use_cache})
14931487
kwargs.update({"cache": self.cache})
14941488
kwargs.update({"cache_config": self.cache_config})
14951489
r = Redis(connection_pool=self.connection_pool_class(**kwargs))
14961490
else:
14971491
r = Redis(
14981492
host=host,
14991493
port=port,
1500-
use_cache=self.use_cache,
15011494
cache=self.cache,
15021495
cache_config=self.cache_config,
15031496
**kwargs,

redis/connection.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from urllib.parse import parse_qs, unquote, urlparse
1414

1515
from redis.cache import (
16-
CacheConfiguration,
16+
CacheConfig,
1717
CacheEntry,
1818
CacheEntryStatus,
1919
CacheFactory,
@@ -879,7 +879,7 @@ def _enable_tracking_callback(self, conn: ConnectionInterface) -> None:
879879
conn._parser.set_invalidation_push_handler(self._on_invalidation_callback)
880880

881881
def _process_pending_invalidations(self):
882-
while self.retry.call_with_retry_on_false(lambda: self.can_read()):
882+
while self.can_read():
883883
self._conn.read_response(push_request=True)
884884

885885
def _on_invalidation_callback(self, data: List[Union[str, Optional[List[bytes]]]]):
@@ -1251,13 +1251,12 @@ def __init__(
12511251
self.connection_kwargs = connection_kwargs
12521252
self.max_connections = max_connections
12531253
self.cache = None
1254-
self._cache_conf = None
12551254
self._cache_factory = cache_factory
12561255
self._scheduler = None
12571256
self._hc_cancel_event = None
12581257
self._hc_thread = None
12591258

1260-
if connection_kwargs.get("use_cache"):
1259+
if connection_kwargs.get("cache_config") or connection_kwargs.get("cache"):
12611260
if connection_kwargs.get("protocol") not in [3, "3"]:
12621261
raise RedisError("Client caching is only supported with RESP version 3")
12631262

@@ -1278,7 +1277,6 @@ def __init__(
12781277

12791278
self._scheduler = Scheduler()
12801279

1281-
connection_kwargs.pop("use_cache", None)
12821280
connection_kwargs.pop("cache", None)
12831281
connection_kwargs.pop("cache_config", None)
12841282

@@ -1494,8 +1492,9 @@ def run_scheduled_healthcheck(self) -> None:
14941492
# Run scheduled healthcheck to avoid stale invalidations in idle connections.
14951493
if self.cache is not None and self._scheduler is not None:
14961494
self._hc_cancel_event = threading.Event()
1495+
hc_interval = self.cache.get_config().get_health_check_interval()
14971496
self._hc_thread = self._scheduler.run_with_interval(
1498-
self._perform_health_check, 2, self._hc_cancel_event
1497+
self._perform_health_check, hc_interval, self._hc_cancel_event
14991498
)
15001499

15011500
def _perform_health_check(self, done: threading.Event) -> None:

redis/retry.py

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -78,35 +78,3 @@ def call_with_retry(
7878
backoff = self._backoff.compute(failures)
7979
if backoff > 0:
8080
sleep(backoff)
81-
82-
def call_with_retry_on_false(
83-
self,
84-
do: Callable[[], T],
85-
on_false: Optional[Callable[[], T]] = None,
86-
max_retries: Optional[int] = 3,
87-
timeout: Optional[float] = 0,
88-
exponent: Optional[int] = 2,
89-
) -> bool:
90-
"""
91-
Execute an operation that returns boolean value with retry
92-
logic in case if false value been returned.
93-
`do`: the operation to call. Expects no argument.
94-
`on_false`: Callback to be executed on retry fail.
95-
"""
96-
res = do()
97-
98-
if res:
99-
return res
100-
101-
if on_false is not None:
102-
on_false()
103-
104-
if max_retries > 0:
105-
if timeout > 0:
106-
time.sleep(timeout)
107-
108-
return self.call_with_retry_on_false(
109-
do, on_false, max_retries - 1, timeout * exponent, exponent
110-
)
111-
112-
return False

0 commit comments

Comments
 (0)