From 75a8a0046b5b2ebd9942b25035b346aa953f81cc Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Thu, 23 Jul 2026 22:36:03 -0400 Subject: [PATCH] refac --- backend/open_webui/utils/redis.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/backend/open_webui/utils/redis.py b/backend/open_webui/utils/redis.py index 1417be134c..bee7f633b2 100644 --- a/backend/open_webui/utils/redis.py +++ b/backend/open_webui/utils/redis.py @@ -14,7 +14,6 @@ from typing import Any from urllib.parse import ParseResult, urlparse import redis as _redis_sync - from open_webui.env import ( REDIS_CLUSTER, REDIS_HEALTH_CHECK_INTERVAL, @@ -33,6 +32,7 @@ _ACCEPTED_SCHEMES = frozenset({'redis', 'rediss'}) _SENTINEL_RETRYABLE = ( _redis_sync.exceptions.ConnectionError, _redis_sync.exceptions.ReadOnlyError, + _redis_sync.exceptions.TimeoutError, ) _FACTORY_METHODS = frozenset({'pipeline', 'pubsub', 'monitor', 'client', 'transaction'}) _CONNECTION_POOL: dict[tuple, Any] = {} @@ -126,10 +126,11 @@ class SentinelRedisProxy: self._sentinel = sentinel self._service_name = service_name self._async_mode = async_mode + self._master: Any | None = None def __getattr__(self, name: str) -> Any: """Proxy attribute access with automatic Sentinel failover retry.""" - current_master = self._sentinel.master_for(self._service_name) + current_master = self._resolve_master() original = getattr(current_master, name) # Non-callable or factory attributes pass through without wrapping. @@ -143,7 +144,12 @@ class SentinelRedisProxy: def _resolve_master(self) -> Any: """Ask Sentinel for the current master connection.""" - return self._sentinel.master_for(self._service_name) + if self._master is None: + self._master = self._sentinel.master_for(self._service_name) + return self._master + + def _clear_master(self) -> None: + self._master = None def _should_retry(self, attempt: int) -> bool: return attempt < REDIS_SENTINEL_MAX_RETRY_COUNT - 1 @@ -184,6 +190,7 @@ class SentinelRedisProxy: except _SENTINEL_RETRYABLE as exc: if proxy._should_retry(attempt): proxy._log_retry(exc, attempt) + proxy._clear_master() if REDIS_RECONNECT_DELAY: await asyncio.sleep(REDIS_RECONNECT_DELAY / 1000) continue @@ -208,6 +215,7 @@ class SentinelRedisProxy: except _SENTINEL_RETRYABLE as exc: if proxy._should_retry(attempt): proxy._log_retry(exc, attempt) + proxy._clear_master() if REDIS_RECONNECT_DELAY: await asyncio.sleep(REDIS_RECONNECT_DELAY / 1000) continue @@ -229,6 +237,7 @@ class SentinelRedisProxy: except _SENTINEL_RETRYABLE as exc: if proxy._should_retry(attempt): proxy._log_retry(exc, attempt) + proxy._clear_master() if REDIS_RECONNECT_DELAY: time.sleep(REDIS_RECONNECT_DELAY / 1000) continue