fix: cannot connect through Redis Sentinels that require a password (#32241)

When the Redis Sentinels are protected with a password, every Redis operation failed with "No master found", because the password in REDIS_URL was used for the Redis server itself but never for the Sentinels. The Sentinels now get the same credentials, both for REDIS_URL and for WEBSOCKET_REDIS_URL. Sentinels without a password keep working, and Sentinel credentials set by hand in WEBSOCKET_REDIS_OPTIONS still take precedence.

Fixes #32240
This commit is contained in:
Classic298 2026-10-12 09:42:26 +02:00 • committed by GitHub
parent d786ed56c9
commit 5ad9af57d1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 20 additions and 1 deletions

View file

@ -58,6 +58,7 @@ from open_webui.utils.chat_id import is_saved_chat_id
from open_webui.utils.json_codec import SOCKETIO_JSON, JSONCodec, dumps_bytes
from open_webui.utils.misc import get_output_text
from open_webui.utils.redis import (
build_sentinel_kwargs,
build_sentinel_url,
get_redis_connection,
get_sentinels_from_env,
@ -103,8 +104,16 @@ if WEBSOCKET_MANAGER == 'redis':
if sentinel_hosts
else WEBSOCKET_REDIS_URL
)
ws_redis_options = (
{
'sentinel_kwargs': build_sentinel_kwargs(WEBSOCKET_REDIS_URL, WEBSOCKET_REDIS_OPTIONS),
**WEBSOCKET_REDIS_OPTIONS,
}
if sentinel_hosts
else WEBSOCKET_REDIS_OPTIONS
)
manager_class = AsyncRedisRoomChannelManager if WEBSOCKET_REDIS_ROOM_CHANNELS else socketio.AsyncRedisManager
redis_manager = manager_class(ws_redis_url, redis_options=WEBSOCKET_REDIS_OPTIONS, json=SOCKETIO_JSON)
redis_manager = manager_class(ws_redis_url, redis_options=ws_redis_options, json=SOCKETIO_JSON)
sio = socketio.AsyncServer(
cors_allowed_origins=SOCKETIO_CORS_ORIGINS,
async_mode='asgi',

View file

@ -86,6 +86,13 @@ def build_sentinel_url(
return f'redis+sentinel://{auth}{nodes}/{cfg["db"]}/{cfg["service"]}'
def build_sentinel_kwargs(base_url: str, redis_options: dict[str, Any]) -> dict[str, Any]:
"""Kwargs for the Sentinel connections: ``base_url`` credentials plus the ``socket_*`` options."""
cfg = parse_redis_url(base_url)
socket_options = {key: value for key, value in redis_options.items() if key.startswith('socket_')}
return {'username': cfg['username'], 'password': cfg['password'], **socket_options}
def get_redis_client(async_mode: bool = False) -> Any | None:
"""Create a Redis connection using settings from environment variables.
@ -283,6 +290,9 @@ def _build_sentinel(
db=cfg['db'],
username=cfg['username'],
password=cfg['password'],
sentinel_kwargs=build_sentinel_kwargs(
url, {'socket_connect_timeout': REDIS_SOCKET_CONNECT_TIMEOUT, **_socket_options()}
),
decode_responses=decode_responses,
socket_connect_timeout=REDIS_SOCKET_CONNECT_TIMEOUT,
**{k: v for k, v in _socket_options().items() if k != 'socket_connect_timeout'},