enh: multiple replica app state sync

This commit is contained in:
Timothy Jaeryang Baek 2025-03-08 17:59:15 +00:00
parent 324cd94c53
commit d40e696468
3 changed files with 35 additions and 3 deletions

View File

@ -3,6 +3,7 @@ import logging
import os import os
import shutil import shutil
import base64 import base64
import redis
from datetime import datetime from datetime import datetime
from pathlib import Path from pathlib import Path
@ -17,6 +18,7 @@ from open_webui.env import (
DATA_DIR, DATA_DIR,
DATABASE_URL, DATABASE_URL,
ENV, ENV,
REDIS_URL,
FRONTEND_BUILD_DIR, FRONTEND_BUILD_DIR,
OFFLINE_MODE, OFFLINE_MODE,
OPEN_WEBUI_DIR, OPEN_WEBUI_DIR,
@ -248,9 +250,14 @@ class PersistentConfig(Generic[T]):
class AppConfig: class AppConfig:
_state: dict[str, PersistentConfig] _state: dict[str, PersistentConfig]
_redis: Optional[redis.Redis] = None
def __init__(self): def __init__(self, redis_url: Optional[str] = None):
super().__setattr__("_state", {}) super().__setattr__("_state", {})
if redis_url:
super().__setattr__(
"_redis", redis.Redis.from_url(redis_url, decode_responses=True)
)
def __setattr__(self, key, value): def __setattr__(self, key, value):
if isinstance(value, PersistentConfig): if isinstance(value, PersistentConfig):
@ -259,7 +266,31 @@ class AppConfig:
self._state[key].value = value self._state[key].value = value
self._state[key].save() self._state[key].save()
if self._redis:
redis_key = f"open-webui:config:{key}"
self._redis.set(redis_key, json.dumps(self._state[key].value))
def __getattr__(self, key): def __getattr__(self, key):
if key not in self._state:
raise AttributeError(f"Config key '{key}' not found")
# If Redis is available, check for an updated value
if self._redis:
redis_key = f"open-webui:config:{key}"
redis_value = self._redis.get(redis_key)
if redis_value is not None:
try:
decoded_value = json.loads(redis_value)
# Update the in-memory value if different
if self._state[key].value != decoded_value:
self._state[key].value = decoded_value
log.info(f"Updated {key} from Redis: {decoded_value}")
except json.JSONDecodeError:
log.error(f"Invalid JSON format in Redis for {key}: {redis_value}")
return self._state[key].value return self._state[key].value

View File

@ -330,7 +330,7 @@ ENABLE_REALTIME_CHAT_SAVE = (
# REDIS # REDIS
#################################### ####################################
REDIS_URL = os.environ.get("REDIS_URL", "redis://localhost:6379/0") REDIS_URL = os.environ.get("REDIS_URL", "")
#################################### ####################################
# WEBUI_AUTH (Required for security) # WEBUI_AUTH (Required for security)

View File

@ -313,6 +313,7 @@ from open_webui.env import (
AUDIT_EXCLUDED_PATHS, AUDIT_EXCLUDED_PATHS,
AUDIT_LOG_LEVEL, AUDIT_LOG_LEVEL,
CHANGELOG, CHANGELOG,
REDIS_URL,
GLOBAL_LOG_LEVEL, GLOBAL_LOG_LEVEL,
MAX_BODY_LOG_SIZE, MAX_BODY_LOG_SIZE,
SAFE_MODE, SAFE_MODE,
@ -419,7 +420,7 @@ app = FastAPI(
oauth_manager = OAuthManager(app) oauth_manager = OAuthManager(app)
app.state.config = AppConfig() app.state.config = AppConfig(redis_url=REDIS_URL)
app.state.WEBUI_NAME = WEBUI_NAME app.state.WEBUI_NAME = WEBUI_NAME
app.state.LICENSE_METADATA = None app.state.LICENSE_METADATA = None