diff --git a/backend/open_webui/env.py b/backend/open_webui/env.py index f612248ffe..1695cec20a 100644 --- a/backend/open_webui/env.py +++ b/backend/open_webui/env.py @@ -435,6 +435,20 @@ REDIS_SOCKET_KEEPALIVE = ( os.environ.get('REDIS_SOCKET_KEEPALIVE', 'False').lower() == 'true' ) +# How often (in seconds) redis-py should PING an idle pooled connection +# before reusing it. Opt-in: defaults to unset (empty string) so behavior +# is unchanged for existing deployments. When set, should be shorter than +# the Redis server `timeout` setting and any firewall/LB idle timeout on +# the path to Redis, so stale connections are detected before a real +# command lands on them. Set to 0 or empty to disable. +REDIS_HEALTH_CHECK_INTERVAL = os.environ.get('REDIS_HEALTH_CHECK_INTERVAL', '') +try: + REDIS_HEALTH_CHECK_INTERVAL = int(REDIS_HEALTH_CHECK_INTERVAL) + if REDIS_HEALTH_CHECK_INTERVAL <= 0: + REDIS_HEALTH_CHECK_INTERVAL = None +except ValueError: + REDIS_HEALTH_CHECK_INTERVAL = None + REDIS_RECONNECT_DELAY = os.environ.get('REDIS_RECONNECT_DELAY', '') if REDIS_RECONNECT_DELAY == '': diff --git a/backend/open_webui/utils/redis.py b/backend/open_webui/utils/redis.py index ec1dee5e9b..61a4d74c7c 100644 --- a/backend/open_webui/utils/redis.py +++ b/backend/open_webui/utils/redis.py @@ -9,6 +9,7 @@ import redis from open_webui.env import ( REDIS_CLUSTER, + REDIS_HEALTH_CHECK_INTERVAL, REDIS_SOCKET_CONNECT_TIMEOUT, REDIS_SOCKET_KEEPALIVE, REDIS_SENTINEL_HOSTS, @@ -202,6 +203,12 @@ def get_redis_connection( {'socket_keepalive': True} if REDIS_SOCKET_KEEPALIVE else {} ) + health_check_kwargs = ( + {'health_check_interval': REDIS_HEALTH_CHECK_INTERVAL} + if REDIS_HEALTH_CHECK_INTERVAL + else {} + ) + if async_mode: import redis.asyncio as redis @@ -217,6 +224,7 @@ def get_redis_connection( decode_responses=decode_responses, socket_connect_timeout=REDIS_SOCKET_CONNECT_TIMEOUT, **keepalive_kwargs, + **health_check_kwargs, ) connection = SentinelRedisProxy( sentinel, @@ -231,6 +239,7 @@ def get_redis_connection( decode_responses=decode_responses, **connect_timeout_kwargs, **keepalive_kwargs, + **health_check_kwargs, ) elif redis_url: connection = redis.from_url( @@ -238,6 +247,7 @@ def get_redis_connection( decode_responses=decode_responses, **connect_timeout_kwargs, **keepalive_kwargs, + **health_check_kwargs, ) else: import redis @@ -253,6 +263,7 @@ def get_redis_connection( decode_responses=decode_responses, socket_connect_timeout=REDIS_SOCKET_CONNECT_TIMEOUT, **keepalive_kwargs, + **health_check_kwargs, ) connection = SentinelRedisProxy( sentinel, @@ -267,6 +278,7 @@ def get_redis_connection( decode_responses=decode_responses, **connect_timeout_kwargs, **keepalive_kwargs, + **health_check_kwargs, ) elif redis_url: connection = redis.Redis.from_url( @@ -274,6 +286,7 @@ def get_redis_connection( decode_responses=decode_responses, **connect_timeout_kwargs, **keepalive_kwargs, + **health_check_kwargs, ) _CONNECTION_CACHE[cache_key] = connection